Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Any way to detect the absense of virtual destructor in base class?

Reply
Thread Tools

Any way to detect the absense of virtual destructor in base class?

 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      11-25-2011
On 25.11.2011 19:30, Juha Nieminen wrote:
> Alf P. Steinbach<(E-Mail Removed)> wrote:
>> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
>>
>> These smart pointers remember the proper derived class destruction to
>> use, freeing you having to have a virtual destructor.

>
> How exactly do they achieve that? If I do, for example, this:
>
> std::unique_ptr<Base*> ptr = new Derived;
>
> then how exactly is 'ptr' able to deduce the derived class destructor in
> order to directly call it when it disposes of the object?
>
> (And where would it store it anyways? I thought the whole idea with
> std::unique_ptr is that its size is that of one pointer, hence making
> it as efficient as a raw pointer.)
>
> I wonder if you are being confused by shared_ptr (and possible other
> smart pointers) being able to destroy an object even if they only see
> a class declaration (rather than a definition), as long as the class was
> fully declared at the point of construction of the pointer. (IOW the class
> doesn't need to be fully declared at the place of destruction.) That's not
> the same thing as a base-class type smart pointer being able to deduce
> the derived-class type destructor.


I'm looking at N3290, which I believe is identical to the final standard.

And there std::unique_ptr stores a deleter, which can be function object
or a function pointer or whatever, specified in constructor call.

Essentially it's the same idea as for shared_ptr's deleter except that
that unique_ptr doesn't use templating to infer the real type of the
object pointer it gets, so one has to write like

unique_ptr<Base> p = unique_ptr<Derived>( new Derived );

The only trouble is, I can't get the deleter functionality to work with
either Visual C++ 10.0 or g++ 4.4.1 in Windows, nor with g++ 4.6.1 in
Ubuntu.

That might indicate that my understanding is wrong (in which case the
deleter argument then seems worthless), or that unique_ptr is not fully
implemented by these compilers, or that N3290 is not identical to C++11?


Cheers, & thanks for focusing me on that,

- Alf
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      11-25-2011
On 25.11.2011 22:25, Alf P. Steinbach wrote:
> On 25.11.2011 19:30, Juha Nieminen wrote:
>> Alf P. Steinbach<(E-Mail Removed)> wrote:
>>> Use `std::unique_ptr` or `std::shared_ptr`, or e.g. `boost::shared_ptr`.
>>>
>>> These smart pointers remember the proper derived class destruction to
>>> use, freeing you having to have a virtual destructor.

>>
>> How exactly do they achieve that? If I do, for example, this:
>>
>> std::unique_ptr<Base*> ptr = new Derived;
>>
>> then how exactly is 'ptr' able to deduce the derived class destructor in
>> order to directly call it when it disposes of the object?
>>
>> (And where would it store it anyways? I thought the whole idea with
>> std::unique_ptr is that its size is that of one pointer, hence making
>> it as efficient as a raw pointer.)
>>
>> I wonder if you are being confused by shared_ptr (and possible other
>> smart pointers) being able to destroy an object even if they only see
>> a class declaration (rather than a definition), as long as the class was
>> fully declared at the point of construction of the pointer. (IOW the
>> class
>> doesn't need to be fully declared at the place of destruction.) That's
>> not
>> the same thing as a base-class type smart pointer being able to deduce
>> the derived-class type destructor.

>
> I'm looking at N3290, which I believe is identical to the final standard.
>
> And there std::unique_ptr stores a deleter, which can be function object
> or a function pointer or whatever, specified in constructor call.
>
> Essentially it's the same idea as for shared_ptr's deleter except that
> that unique_ptr doesn't use templating to infer the real type of the
> object pointer it gets, so one has to write like
>
> unique_ptr<Base> p = unique_ptr<Derived>( new Derived );
>
> The only trouble is, I can't get the deleter functionality to work with
> either Visual C++ 10.0 or g++ 4.4.1 in Windows, nor with g++ 4.6.1 in
> Ubuntu.
>
> That might indicate that my understanding is wrong (in which case the
> deleter argument then seems worthless), or that unique_ptr is not fully
> implemented by these compilers, or that N3290 is not identical to C++11?


I asked it also on SO,

http://stackoverflow.com/questions/8...nique-ptr-work

Cheers,

- Alf


 
Reply With Quote
 
 
 
 
Joe keane
Guest
Posts: n/a
 
      11-25-2011
fire them
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      11-25-2011
Alf P. Steinbach <(E-Mail Removed)> wrote:
> I'm looking at N3290, which I believe is identical to the final standard.
>
> And there std::unique_ptr stores a deleter, which can be function object
> or a function pointer or whatever, specified in constructor call.


If std::unique_ptr is indeed specified to store a pointer to a deleter
function (or a deleter object), then it's a bit disappointing.

When I read that std::unique_ptr would be a better replacement for
std::auto_ptr, I was assuming that it's a smart pointer that is as
efficient as a raw pointer (at least in terms of size), which destroys
the managed object automatically (the advantage over std::auto_ptr being
that it's safe to use in data containers such as std::vector, which may
move its elements around when reallocating, inserting in the middle or
eg. sorting).

However, if std::unique_ptr is (at least) the size of *two* pointers,
it immediately becomes inferior to a raw pointer in terms of efficiency.
While in many/most cases that doesn't matter, it's a bummer in situations
where it would.

I understand the advantage of having a pointer to a deleter in the smart
pointer object: It allows safely deleting an object even in contexts where
the class has only been declared (rather than defined), plus some other
situations (such as using a specialized deleter for the managed object).
However, these situations are quite unusual in practice, and I find it
questionable why one has to pay for something that isn't used, which goes
against one of the core principles of C++. (After all, this principle is
the very reason why eg. classes do not have virtual tables by default,
but only if there specifically are virtual functions. You don't have to
pay for what you don't use.)

Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
using some kind of empty base class optimization trick) in cases where
no deleter is explicitly specified?
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      11-25-2011
On 11/26/11 11:21 AM, Joe keane wrote:
> fire them


Fire who? There isn't a premium charged for quoting context.

--
Ian Collins
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      11-26-2011
On 25.11.2011 23:30, Juha Nieminen wrote:
> Alf P. Steinbach<(E-Mail Removed)> wrote:
>> I'm looking at N3290, which I believe is identical to the final standard.
>>
>> And there std::unique_ptr stores a deleter, which can be function object
>> or a function pointer or whatever, specified in constructor call.

>
> If std::unique_ptr is indeed specified to store a pointer to a deleter
> function (or a deleter object), then it's a bit disappointing.
>
> When I read that std::unique_ptr would be a better replacement for
> std::auto_ptr, I was assuming that it's a smart pointer that is as
> efficient as a raw pointer (at least in terms of size), which destroys
> the managed object automatically (the advantage over std::auto_ptr being
> that it's safe to use in data containers such as std::vector, which may
> move its elements around when reallocating, inserting in the middle or
> eg. sorting).
>
> However, if std::unique_ptr is (at least) the size of *two* pointers,
> it immediately becomes inferior to a raw pointer in terms of efficiency.
> While in many/most cases that doesn't matter, it's a bummer in situations
> where it would.


Yes, that is the case, sorry.

>
> I understand the advantage of having a pointer to a deleter in the smart
> pointer object: It allows safely deleting an object even in contexts where
> the class has only been declared (rather than defined), plus some other
> situations (such as using a specialized deleter for the managed object).
> However, these situations are quite unusual in practice, and I find it
> questionable why one has to pay for something that isn't used, which goes
> against one of the core principles of C++. (After all, this principle is
> the very reason why eg. classes do not have virtual tables by default,
> but only if there specifically are virtual functions. You don't have to
> pay for what you don't use.)


I agree.


> Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
> using some kind of empty base class optimization trick) in cases where
> no deleter is explicitly specified?


I'm not sure.

Anyway I misunderstood the deleter thing. As someone pointed out on SO,
with unique_ptr the deleter type is a template argument for the /type/.
And it doesn't work (directly) for the usage where you allocate as
derived and delete as base, without virtual destructor.

However, I managed to browbeat the unique_ptr functionality into doing
that, by applying a little type erasure:


<code>
#include <iostream>
#include <memory> // std::unique_ptr
#include <functional> // function
#include <utility> // move
#include <string>
using namespace std;

class Base
{
public:
Base() { cout << "Base:<init>" << endl; }
~Base() { cout << "Base::<destroy>" << endl; }
};

class Derived
: public Base
{
public:
Derived() { cout << "Derived::<init>" << endl; }
~Derived() { cout << "Derived::<destroy>" << endl; }
};

class BoundDeleter
{
private:
typedef void (*DeleteFunc)( void* p );

DeleteFunc deleteFunc_;
void* pObject_;

template< class Type >
static void deleteFuncImpl( void* p )
{
delete static_cast< Type* >( p );
}

public:
template< class Type >
BoundDeleter( Type* pObject )
: deleteFunc_( &deleteFuncImpl< Type > )
, pObject_( pObject )
{}

BoundDeleter( BoundDeleter&& other )
: deleteFunc_( move( other.deleteFunc_ ) )
, pObject_( move( other.pObject_ ) )
{}

void operator() (void*) const
{
deleteFunc_( pObject_ );
}
};

template< class Type >
class SafeCleanupUniquePtr
: public unique_ptr< Type, BoundDeleter >
{
public:
typedef unique_ptr< Type, BoundDeleter > Base;

template< class ActualType >
SafeCleanupUniquePtr( ActualType* p )
: Base( p, BoundDeleter( p ) )
{}

template< class Other >
SafeCleanupUniquePtr( SafeCleanupUniquePtr< Other >&& other )
: Base( move( other ) )
{}
};

int main()
{
SafeCleanupUniquePtr< Base > p( new Derived );
}
</code>


Cheers,

- Alf
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      11-26-2011
Alf P. Steinbach <(E-Mail Removed)> wrote:
>> Or is std::unique_ptr able to elide storing a deleter pointer (eg. by
>> using some kind of empty base class optimization trick) in cases where
>> no deleter is explicitly specified?

>
> I'm not sure.


I did what I should have done earlier, and tested it. In a 64-bit system
using gcc 4.6.1 both sizeof(int*) and sizeof(std::unique_ptr<int>) are 8,
so I suppose it is smart enough to avoid reserving space for an unneeded
deleter pointer.

That means I was too hasty to be disappointed with std::unique_ptr.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Absense of bool AommiK C Programming 73 11-26-2007 08:03 AM
Can abstract base class have V-table?, Will the pointer to virtual destructor be entered into the virtual table? sojin C++ 12 04-07-2006 09:02 AM
Explicit destructor calls from inside base class destructor frs C++ 20 09-21-2005 09:22 AM
Format of compiler generated derived destructor when base has 'virtual ~base() throw():" qazmlp C++ 1 04-10-2005 03:09 PM
Virtual destructor for virtual base class? Chunhui Han C++ 2 06-24-2004 10:13 AM



Advertisments