3

我试图在我的代码中使用 auto_ptr,但显然出了点问题。

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

奇怪的是Class实例化后Class对象存在,所以调用s.GetModelMean(Class),Class不为空。但是退出函数 GetM 后,Class 为空,因此不再可用。调用函数 Draw 时发生崩溃。

我通过以下方式声明了这些函数:

int GetM(auto_ptr<ClassType> aM); 

似乎班级被破坏了,但我不明白为什么......

4

4 回答 4

6

您大喊不要将 auto_ptr 作为函数的参数。要么做:

int GetM(const auto_ptr<ClassType>&)

或者

int GetM(ClassType&)

或者

int GetM(ClassType*)

(也可能与 const 一起使用 - 取决于您使用它做什么)。第一个你会以同样的方式调用,你会这样调用第二个函数:

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

最后一个没有星星。

原因是:GetM 会复制 auto_ptr(不是 Class 对象),并在返回时销毁 auto_ptr。auto_ptr (它是一个范围指针或唯一指针 - 不是引用计数器!)将破坏类。

无论如何:auto_ptr 很坏。只要有可能(您的编译器已经支持 C++11 的一些小部分),请使用 std::unique_ptr 和 std::shared_ptr (最后一个进行引用计数)。unique_ptr 不会让你像那样弄乱它(因为不允许复制它 - 恕我直言更有意义)。

于 2012-07-12T06:35:59.387 回答
1

auto_ptr 有一个与源对象混淆的“神奇”复制构造函数。通过将参数按值传递给您的函数,您触发了对复制构造函数的调用,并使原始 auto_ptr 处于它不指向任何内容的状态。

于 2012-07-12T06:32:35.300 回答
0

打电话的原因

int GetM(auto_ptr<ClassType> aM); 

破坏给定对象是auto_ptr在复制对象时具有相当令人惊讶的行为;它不仅修改目标对象,还修改对象。如果你这样做

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

x存储的指针移动yx设置为空)。

这意味着std::auto_ptr非常不适合传递值或将它们存储在容器中(因为容器倾向于在内部复制对象)。它适用于确保某些对象在退出某个范围时被销毁 - 例如使代码异常安全。所以有类似的东西

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

或者

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;
};

其实很好,可以简化代码。

拥有std::auto_ptr意味着拥有所有权。因此,在您的特定情况下,我建议调整GetM签名以使其采用普通指针。

于 2012-07-12T06:44:16.233 回答
0

auto_ptr使用了一个小技巧,这样每当您将 A“复制”到 B 时,B 都会获取对象并清除 A。您可以使用它来非常清楚地声明所有权传递语义(来源:Scott Meyers 和 Andrei Alexandrescus 的书籍。顺便说一句,如果您想了解更多信息,请阅读 Effective C++)。

当然,如果可能的话,你应该使用unique_ptr(你可以把它放在向量中!)来自 C++0x 或来自 Boost 而不是auto_ptr,因为auto_ptr已弃用。

如果您对技巧细节感兴趣,请知道没有神奇的复制构造函数。根本没有复制构造函数。复制构造函数采用 const 引用,您将无法清除复制的对象。所以当你写

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

a1 首先被强制转换为某个临时对象。强制转换运算符采用非常量引用并清除 a1。然后 a2 被这个临时对象初始化。

于 2012-07-12T07:03:34.643 回答