Domanda

I've been looking at some code I'm working on, and we have the equivalent of this:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Detach());

Where AutoPtr is our version of auto_ptr, and Detach() returns the owned pointer and resets itself. Also, B() takes ownership of x.

Now, I realized that this will leak x if new throws an std::bad_alloc, so I changed the code to this:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Get());
x.Detach();

But then I realized that if B() 'owns' the pointer, and an exception happens during its construction, it should take care of deleting the parameter itself (or should it?), so the x will get deleted twice, once by B(), and once by x's destructor.

Now, is there a C++ idiom that gets around this problem, for example, making code that calls constructors responsible for cleaning up parameters? Most code I've seen doesn't seem to do that...

È stato utile?

Soluzione

The obvious solution seems to be to pass a temporary AutoPtr<A> to the constructor of B:

AutoPtr<B> y(new B(AutoPtr<A>(x));

(this also adds resource control for the B* returned from new B()).

B's constructor would just call x.Detach() to initialize whatever it needs to initialize with the A*. If an exception occurs at any point, the AutoPtr<A> will release the object.

If you want to retain the A object managed by x in case of an exception, you can pass a AutoPtr<A>& to the constructor of B instead.

Altri suggerimenti

...it should take care of deleting the parameter itself (or should it?)

No, it should not.

B doesn't exist until the constructor completes, and if it doesn't exist it shouldn't claim ownership of anything (to a point; if the constructor itself did something, that needs to be safe as well).

The C++ idiom is to not use raw pointers for ownership (including for y)! B should accept the AutoPtr as an argument so the caller can give up ownership this way. This is the goal of std::unique_ptr and std::move:

std::unique_ptr<A> x;

std::unique_ptr<B> y(new B(std::move(x)));

Also note that really new should not be used like this as well; instead use the make_* utilities:

auto y = std::make_unique<B>(std::move(x));

But this is missing currently as oversight.

Something like this, may be:

B* y = new B();
y->Attach(x.Detach());

or

B* y = new B();
(*y) = x;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top