smart pointer incomplete type
Jan 5, 2017 at 8:03am UTC
//file: a.h
1 2 3 4 5 6 7 8
#pragma once
#include <iostream>
struct A {
~A() {
std::cout << "~A" << std::endl;
}
};
//file: b.h
1 2 3 4 5 6 7 8 9
#pragma once
#include <memory>
class A;
struct B {
B();
//A is incomplete type
std::shared_ptr<A> pa_;
};
//b.cpp
1 2 3 4 5 6
#include "b.h"
#include "a.h"
B::B():pa_{ new A{} }
{
}
//main.cpp:main function
1 2 3 4 5 6 7
#include "b.h"
int main() {
{
B b;
}
}
I think that "~A" will not be outputed, because class A is an incomplete type in B's destructor.
But gcc 6.2 and vs2015 both output "~A".
Jan 5, 2017 at 9:15am UTC
The (shared) control block of a
std::shared_ptr<> object holds the deleter; the deleter is type-erased. Unlike
std::unique_ptr<> , the deleter is not a template parameter.
The type-erased deleter is instantiated when an instance of the
shared_ptr<> is first attached to a shared object; at that point, what is the associated deleter would be known.
Type-erasure:
http://davekilian.com/cpp-type-erasure.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
#include <iostream>
#include <memory>
struct A ;
struct B
{
B() ;
B(int ) ;
std::shared_ptr<A> pa ;
static A sa ;
};
struct A
{
static void * operator new ( std::size_t sz ) { return ::operator new (sz) ; }
static void operator delete ( void * ptr )
{
std::cout << "A::operator delete\n" ;
::operator delete (ptr) ;
}
static void * operator new []( std::size_t sz ) { return ::operator new [](sz) ; }
static void operator delete []( void * ptr ) { ::operator delete (ptr) ; }
};
A B::sa ;
B::B() : pa( new A ) {} // default deleter (delete A)
// custom do_nothing deleter
B::B(int ) : pa( std::addressof(sa), []( A* ) { std::cout << "do nothing\n" ; } ) {}
int main()
{
{
std::cout << "instantiate with default deleter\n" ;
B b ;
} // A::operator delete
std::cout << "\n-----------------------\n" ;
{
std::cout << "instantiate with do nothing deleter\n" ;
B b(100) ;
} // do nothing
std::cout << "\n-----------------------\n" ;
std::shared_ptr<A> pa ; // the deleter does not contribute to the type of pa
pa = std::shared_ptr<A>( new A ) ;
// the type-erased deleter associated with pa is now the default deleter
pa = nullptr ; // A::operator delete
std::cout << "\n-----------------------\n" ;
pa = std::shared_ptr<A>( nullptr , []( A* ) { std::cout << "hello world!\n" ; } ) ;
// the type-erased deleter associated with pa is now our 'hello world!' deleter
pa = nullptr ; // Hello World!
}
http://coliru.stacked-crooked.com/a/a9bacf56a3f2875e
http://rextester.com/TUDBJ94142
Needles to say, the allocator that the control block holds is also type-erased
(or else things like
std::allocate_shared<>() wouldn't work.)
Last edited on Jan 5, 2017 at 9:20am UTC
Topic archived. No new replies allowed.