سؤال

I am trying to use the auto_ptr in my code, but apparently something goes wrong.

auto_ptr<ClassType> Class(s.Build(aFilename)); //Instantiation of the Class object
int vM = s.GetM(Class);
int vS = s.Draw(Class);

The strange thing is that after the instantiation of Class, the Class object exist and so by calling s.GetModelMean(Class), Class is not empty. But after exiting the function GetM, Class is empty and so not usable anymore. A crash occurs when calling the function Draw.

I declared the functions the following way:

int GetM(auto_ptr<ClassType> aM); 

It seems that the class is destroyed, but I do not understand why...

هل كانت مفيدة؟

المحلول

You shout not give an auto_ptr as an argument to a function. Either do:

int GetM(const auto_ptr<ClassType>&)

or

int GetM(ClassType&)

or

int GetM(ClassType*)

(may be also with const - depends what you are doing with it). The first you would call the same way, the second function you would call like this:

int vM = s.GetM(*Class.get())

the last without the star.

The reason is: GetM will copy the auto_ptr (not the Class object) and destroy the auto_ptr when it returns. The auto_ptr (which is a scope pointer or unique pointer - not a reference counter!) will than destroy Class.

Anyway: auto_ptr is very broken. Whenever possible (your compiler already supports some small parts of C++11), use std::unique_ptr and std::shared_ptr (last one does reference counting). unique_ptr will not allow you to mess around with it like that (since copying it is not allowed - which imho makes much more sense).

نصائح أخرى

auto_ptr has a "magical" copy constructor that messes with the source object. By passing arguments by value to your function, you trigger the call to copy constructor, and leave the original auto_ptr in the state where it points to nothing.

The reason that calling

int GetM(auto_ptr<ClassType> aM); 

destructs the given object is that auto_ptr has a fairly surprising behaviour when copying objects; it not only modifies the destination object, it also modifies the source object. Do if you do

std::auto_ptr<int> y = x;  // modifies x *and* y

The pointer stored in x is moved to y (x is set to null).

This means that std::auto_ptr is very inappropriate for passing values around or storing them in containers (since containers tend to copy objects around internally). It is appropriate for making sure that some object gets destroyed when exiting some scope - for instance to make code exception safe. So having something like

void f() {
  std::auto_ptr<int> x = new int;
  ...
  // no need to delete anything, destroying 'x' will delete
}

Or

class Widget {
public:
  Widget() : m_myData( new int ) { }

private:
  Widget(const Widget &other); // disabled
  void operator=( const Widget &other ); // disabled

  std::auto_ptr<int> m_myData;
};

Is actually fine and can simplify code.

Having a std::auto_ptr means having ownership. So in your particular case, I'd suggest to adjust the GetM signature so that it takes a plain pointer.

auto_ptr uses a little trick so that whenever you "copy" A to B, B gets the object and A is cleared. You can use this to declare ownership passing semantics very clearly (source: Scott Meyers and Andrei Alexandrescus books. Btw, if you want to know more, read Effective C++).

Of course, if possible, you should use unique_ptr (you can put it in vectors!) from C++0x or from Boost instead of auto_ptr, as auto_ptr is deprecated.

If you are interested in the trick details, know that there is no magic copy constructor. There is no copy constructor at all. Copy constructor takes const reference, and you would not be able to clear the copied object. So when you write

std::auto_ptr<A> a1(new A);
std::auto_ptr<A> a2(a1);

a1 is first casted to some temporary object. The cast operator takes non-const reference and clears a1. Then a2 is initialized by this temporary object.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top