shared_ptr to incomplete type, undefined behavior?

A

Alan Johnson

From the standard 5.3.5/5:
"If the object being deleted has incomplete class type at the point of
deletion and the complete class has a non-trivial destructor or a
deallocation function, the behavior is undefined."

In the program below, what constitutes "point of deletion"? Presumably,
since delete is called somewhere within shared_ptr's template, the point
of deletion is the same place at which the template is instantiated.

Does the following program therefore exhibit undefined behavior, or am I
missing something? (Does this generalize to all cases in which a
shared_ptr is created from a forward reference?)


#include <iostream>
#include <boost/shared_ptr.hpp>

// Forward reference.
class A ;

// A has incomplete type here.
boost::shared_ptr<A> pa ;

class A
{
public:
A() { std::cout << "A()" << std::endl ; }
~A() { std::cout << "~A()" << std::endl ; }
} ;

int main()
{
pa.reset(new A) ;
}
 
A

Alf P. Steinbach

* Alan Johnson:
From the standard 5.3.5/5:
"If the object being deleted has incomplete class type at the point of
deletion and the complete class has a non-trivial destructor or a
deallocation function, the behavior is undefined."

In the program below, what constitutes "point of deletion"? Presumably,
since delete is called somewhere within shared_ptr's template, the point
of deletion is the same place at which the template is instantiated.
>

Does the following program therefore exhibit undefined behavior, or am I
missing something? (Does this generalize to all cases in which a
shared_ptr is created from a forward reference?)


#include <iostream>
#include <boost/shared_ptr.hpp>

// Forward reference.
class A ;

// A has incomplete type here.
boost::shared_ptr<A> pa ;

class A
{
public:
A() { std::cout << "A()" << std::endl ; }
~A() { std::cout << "~A()" << std::endl ; }
} ;

int main()
{
pa.reset(new A) ;
}

If you move the definition of class A to a separate file, plus a factory
function f that produces a raw pointer, and use f in 'main' instead of
direct use of 'new', then yes, in that case you would have UB --
except that the Boost code checks for this, so it won't compile:

// verify that types are complete for increased safety

template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}

However, as your code is it compiles, at least with MSVC 7.1, and so
(what an argument!) I think the instantiation of the template is at the
point of actual usage in 'main'.

Note that boost::shared_ptr provides a way to avoid UB even when you do
have an incomplete type, by passing a deleter function to the
constructor (that's why boost::shared_ptr is great for the PIMPL idiom).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top