代码之家  ›  专栏  ›  技术社区  ›  Srikanth

将std::auto_ptr作为成员变量的类的对象存储在std::vector中安全吗?

  •  3
  • Srikanth  · 技术社区  · 17 年前

    class MyClass
    {
    private:
      std::auto_ptr<MyOtherClass> obj;
    };
    

    read here

    8 回复  |  直到 9 年前
        1
  •  6
  •   bayda    17 年前

    这是不安全的,因为当容器将复制MyClass instnace时,默认的复制运算符将为所有成员调用copy,也为auto_ptr成员调用copy。我们将遇到与您在问题中描述的情况相同的情况(将auto_ptr存储在容器中)

    顺便说一句:为了避免编译时的混淆,请添加

    private:
      MyClass& operator=( const MyClass& );  
      MyClass( const MyClass& );
    

    如果您尝试使用复制运算符,编译器输出错误,这可以为您节省数小时的调试时间。

        2
  •  3
  •   Benoît photo_tom    17 年前

    正如Neil Butterworth所说,auto_ptr可能不是正确的选择。

    boost::shared_ptr 很明显,但你说你不能使用boost。

    让我提一下,你可以下载boost,只使用 bcp tool 和使用 boost::shared_ptr 。这只意味着您的项目中添加了一些hpp文件。我认为这是正确的做法。

        3
  •  3
  •   Community Mohan Dere    6 年前

    它是 在标准容器中包含auto_ptr的对象是有效的。你遇到了未定义的行为。两个常见问题:

    • std::向量<>::resize将其参数复制到每个创建的元素中。第一个副本将“成功”(见下文为什么不成功),但每个后续副本都将为空,因为复制的元素也是空的!
    • push_back 如果抛出异常,则不得产生任何影响。因此,你的一些元素现在是空的。

    因为这都是关于未定义的行为,所以这并不重要。但即使 如果 我们试图根据我们认为有效的东西来提出这种行为,无论如何我们都会失败。所有成员的功能如下 push_back , resize 等等都有一个常量引用,它接受T类型的对象。因此,类型为的引用 T const& 试图复制到向量的元素中。但是隐式创建的复制构造函数/复制赋值运算符看起来像 T(T&) -也就是说,它需要一个 非常量 要复制的对象!标准库的良好实现会检查这一点,并在必要时无法编译。

    在下一个C++版本之前,你必须接受这一点。下一个将支持以下元素类型 可移动的 也就是说,移动的对象不需要等于移动到的对象。这将允许放置 , 所有权转移指针 线程 放入容器中。

    查看标准对此有何规定( 17.4.3.6

    在某些情况下(替换函数、处理函数、用于实例化标准库模板组件的类型操作),C++标准库依赖于C++程序提供的组件。如果这些组件不符合其要求,则本标准对实施没有要求。

    特别是,在以下情况下,影响尚未确定:

    • 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作没有实现适用需求子条款(20.1.5、23.1、24.1、26.1)的语义。
        4
  •  2
  •   Community Mohan Dere    9 年前

    我发布了一个问题作为跟进 关于这个答案,请参见 Class containing auto_ptr stored in vector .

    由于你的类没有用户定义的复制构造函数,那么不,它可能(见下文)不安全。当你的类被复制时(就像它被添加到向量时一样),将使用auto_ptr的复制构造函数。这有一种奇怪的行为,即将被复制的东西的所有权转移到副本上,因此被复制的物体的指针现在为空。

    虽然不太可能,但你确实想要这种行为,在这种情况下,auto_ptr是安全的。如果你不这样做,你也应该:

    • 添加复制构造函数来管理复制

    请注意,这还不够——有关更多信息,请参阅上述后续问题。

    或者:

    • 使用更智能的、可能有引用计数的指针,例如boost智能指针之一
        5
  •  1
  •   anon anon    17 年前

    复制MyClass对象将导致调用赋值运算符或复制构造函数。如果它们没有重载以处理auto_ptr<>它们将以不同寻常的方式将对复制构造函数(或赋值运算符)的调用传播到auto_ptr<>成员。这可能会导致您链接的问题中描述的问题。

        6
  •  1
  •   yves Baumes    17 年前

    实例化auto_pointer向量不安全的原因是有一个算法:sort(),它会在堆栈上复制容器中的一个对象。(sort()实现了快速排序,需要一个“枢轴”) 因此,在退出sort()函数的scpope时将其删除。

    在你的例子中,很简单,你必须确保你的类不会像auto_ptr那样运行,或者确保你永远不会调用可以删除底层对象的函数/算法。根据我的看法,第一种解决方案是最好的:)

    所以,您的复制构造函数和做作运算符也不应该放弃指针对象的属性。

    实现这一点的最佳方法是包装一个boost智能指针而不是auto_ptr,以便在调用此类函数/算法时使容器安全。

    顺便说一句,根据我的说法,定义一个更好的复制构造函数/affectition运算符来绕过这个问题并不是一个好的解决方案:我看不到一个可以保证应用sort()算法结果安全的好的复制构造函数实现(以及affectition操作符)。

        7
  •  1
  •   Salman A    17 年前

    如果你想在容器中使用一个使用auto_ptr的类,你可以自己提供一个复制构造函数和赋值运算符:

    class MyClass
    {
    private:
      const std::auto_ptr<MyOtherClass> obj; // Note const here to keep the pointer from being modified.
    
    public:
      MyClass(const MyClass &other) : obj(new MyOtherClass(*other.obj)) {}
      MyClass &operator=(const MyClass &other)
      {
          *obj = *other.obj;
          return *this;
      }
    };
    

    但正如其他地方提到的,该标准允许容器进行复制和赋值,并假设所包含的类将以特定的方式运行 auto_ptr 违反。通过定义上述方法,您可以使包含auto_ptr的类表现良好。即使您的实现与 auto_ptrs ,你可能会发现另一个实现不起作用。该标准只保证性能和可观察行为,而不是实现。

        8
  •  0
  •   Edouard A.    17 年前