Вопрос

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...

Это было полезно?

Решение

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.

Другие советы

...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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top