C++ using scoped_ptr as a member variable

scoped_ptr is very good for this purpose. But one has to understand its semantics. You can group smart pointers using two major properties:

  • Copyable: A smart pointer can be copied: The copy and the original share ownership.
  • Movable: A smart pointer can be moved: The move-result will have ownership, the original won’t own anymore.

That’s rather common terminology. For smart pointers, there is a specific terminology which better marks those properties:

  • Transfer of Ownership: A smart pointer is Movable
  • Share of Ownership: A smart pointer is copyable. If a smart pointer is already copyable, it’s easy to support transfer-of-ownership semantic: That then is just an atomic copy & reset-of-original operation, restricting that to smart pointers of certain kinds (e.g only temporary smart pointers).

Let’s group the available smart pointers, using (C)opyable, and (M)ovable, (N)either:

  1. boost::scoped_ptr: N
  2. std::auto_ptr: M
  3. boost::shared_ptr: C

auto_ptr has one big problem, in that it realizes the Movable concept using a copy constructor. That is because When auto_ptr was accepted into C++, there wasn’t yet a way to natively support move semantics using a move constructor, as opposed to the new C++ Standard. That is, you can do the following with auto_ptr, and it works:

auto_ptr<int> a(new int), b;
// oops, after this, a is reset. But a copy was desired!
// it does the copy&reset-of-original, but it's not restricted to only temporary
// auto_ptrs (so, not to ones that are returned from functions, for example).
b = a; 

Anyway, as we see, in your case you won’t be able to transfer the ownership to another object: Your object will in effect be non-copyable. And in the next C++ Standard, it will be non-movable if you stay with scoped_ptr.

For implementing your class with scoped_ptr, watch that you either have one of these two points satisfied:

  • Write an destructor (even if it’s empty) in the .cpp file of your class, or
  • Make Owned a completely defines class.

Otherwise, when you would create an object of Example, the compiler would implicitly define a destructor for you, which would call scoped_ptr’s destructor:

~Example() { ptr.~scoped_ptr<Owned>(); }

That would then make scoped_ptr call boost::checked_delete, which would complain about Owned being incomplete, in case you haven’t done any of the above two points. If you have defined your own dtor in the .cpp file, the implicit call to the destructor of scoped_ptr would be made from the .cpp file, in which you could place the definition of your Owned class.

You have that same problem with auto_ptr, but you have one more problem: Providing auto_ptr with an incomplete type is undefined behavior currently (maybe it will be fixed for the next C++ version). So, when you use auto_ptr, you have to make Owned a complete type within your header file.

shared_ptr doesn’t have that problem, because it uses a polymorphic deleter, which makes an indirect call to the delete. So the deleting function is not instantiated at the time the destructor is instantiated, but at the time the deleter is created in shared_ptr’s constructor.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)