0

I have abstract class Managee and helper class Wrapper. Pointer to Managee used to construct Wrapper, then Wrapper will take ownership over Managee. I want to ensure that user will always allocate new Managee. Are rvalue-references suitable for this goal?

Wrapper definition:

...
Wrapper(Managee * && tmpptr);
Managee & GetManagee();
...

Wrapper usage:

Wrapper a(new ManageeA()); // ok;
Wrapper b(&a.GetManagee()); // error?    <-----
Xeo
  • 129,499
  • 52
  • 291
  • 397
Shadows In Rain
  • 1,140
  • 12
  • 28

1 Answers1

3

Rvalue-references don't help, since &a.GetManagee() is an rvalue. Why not take a std::unique_ptr?

Wrapper(std::unique_ptr<Managee> ptr)
  : member_ptr(std::move(ptr)) {}

Managee& GetManagee();

Usage:

Wrapper a(make_unique<Managee>(/*args*/));

For make_unique, see here.

The best solution, however, wouldn't even allow the user to create a Managee's derived types on the stack - this can be done with a factory function (of course with std::unique_ptr) and making constructors private:

class SomeClass : public Managee{
public:
  static std::unique_ptr<SomeClass> create(){
    return make_unique<SomeClass>();
  }
private:
  SomeClass(){}
  // other ctors
};
Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 3
    I'd suggest making destructor private and passing custom deleter to `unique_ptr` inside `SomeClass` like this `[](SomeClass* ptr) { delete ptr; }`. I prefer this because, for every possible constructor you need to make corresponding 'create' method. – zahir Nov 04 '12 at 00:56
  • @zahir: Actually, thinking about it, it's not that great. First, you can just make `create` a variadic function template and perfect-forward all arguments. The bigger problem with your solution, however, is the following: To control who can destroy a `SomeClass`, you need to make the deleter a private class-type. If it was public, everyone could use it. But then, a user of your class can't just say `unique_ptr`, so you need to provide a typedef, like `typedef unique_ptr pointer;` inside `SomeClass`. – Xeo Nov 04 '12 at 01:41
  • 1
    (continued) With this, your users need to say `SomeClass::ptr p(new SomeClass());`. However, everyone can still access the deleter by simply doing `decltype(p.get_deleter())`. So, no matter how you try to make only `unique_ptr` be able to destroy your class, it's not possible as long as you expose the `unique_ptr`. A solution might be making the deleter simply public and using the [passkey pattern](http://stackoverflow.com/q/3324898/500104), but *meh*, since you can, as I said, simply make `create` a variadic template. – Xeo Nov 04 '12 at 01:47
  • Oh, I wasn't aware of `get_deleter` (yes, I am usually lousy reading specs). If I can take that deleter and call, how can a smart pointer keeps track of the owned pointer? – zahir Nov 04 '12 at 12:04
  • @zahir: As is so often with C++, they trust you to not screw up. :) – Xeo Nov 04 '12 at 13:02