将具有 std::auto_ptr 作为其成员变量的类的对象存储在 std::vector 中是否安全?

发布于 2024-07-16 16:56:43 字数 362 浏览 5 评论 0原文

我不能在我的项目中使用shared_ptr,没有boost:(

所以,我有一个与下面的类大致相似的类:

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

现在,我想将上述类的实例存储在std::vector中。安全吗?我在这里读到这是错误的将 std::auto_ptr 与 STL 容器一起使用是否适用于我的情况?

I can't use shared_ptr in my project, no boost :(

So, I'm having a class roughly similar to the one below:

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

Now, I want to store the instances of above class in std::vector. Is it safe? I've read here that it's wrong to use std::auto_ptr with STL containers. Does it apply to my situation here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

耀眼的星火 2024-07-23 16:56:43

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

顺便说一句:为了避免混淆 在编译时添加编译器输出错误,这可以节省您数小时的调试时间。

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

如果您尝试使用复制运算符,则

It is not safe, bacause when container will copy MyClass instnace default copy operator will call copy for all members - and for auto_ptr member too and we will have same situation as you describe in your question ( storing auto_ptr in container )

BTW: for avoid confusion at compile time add

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

compiler output error if you will try use copy operators, this can save you from hours of debug.

美胚控场 2024-07-23 16:56:43

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

boost::shared_ptr显然是,但你说你不能使用升压。

让我提一下,您可以下载 boost,仅使用 bcp 工具 并使用 boost::shared_ptr。 这仅意味着您的项目中添加了一些 hpp 文件。 我相信这是正确的道路。

As Neil Butterworth said, auto_ptr is probably not the way to go.

boost::shared_ptr clearly is, but you say you can't use boost.

Let me mention that you could download boost, extract what you need for shared\ptr only using the bcp tool and use boost::shared_ptr. It would only mean a few added hpp files in your project. I believe it's the right way to go.

温馨耳语 2024-07-23 16:56:43

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

  • std::vector<>::resize 将其参数复制到每个创建的元素中。 第一个副本将“成功”(见下文为什么不成功),但以后的每个副本都将是空的,因为复制的元素也是空的!
  • 如果在重新分配期间发生异常,您可能会碰巧复制了一些元素(到新缓冲区) - 但副本被丢弃 - 而其他元素则不会,因为如果发生异常, push_back 一定不会产生任何影响正在被抛出。 因此,您的一些元素现在是空的。

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

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

查看标准对此的规定 (17.4.3.6):

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

特别是,在以下情况下效果未定义:

  • 对于实例化模板组件时用作模板参数的类型,如果类型上的操作未实现适用的要求子条款(20.1.5、23.1、24.1、26.1)的语义。

It is not valid to have an object that contains an auto_ptr in a standard container. You run into undefined behavior. Two common problems:

  • std::vector<>::resize copies its argument into each created element. The first copy will "succeed" (see below why not), but each further copy will be empty, because the element copied is also empty!
  • If something during reallocation throws, you can happen to have some elements copied (to a new buffer) - but the copy being thrown away - and other elements not, because push_back must not have any effects if an exception is being thrown. Thus some of your elements are now empty.

As this is all about undefined behavior it does not really matter. But even if we try to come up with this behavior based on what we think is valid, we would fail anyway. All the member functions like push_back, resize and so on have a const reference that takes an object of type T. Thus, a reference of type T const& is tried to copied into elements of the vector. But the implicitly created copy constructor/copy assignment operator looks like T(T&) - that is, it requires a non-const object to be copied from! Good implementations of the Standard library check that, and fail to compile if necessary.

Until the next C++ version, you have to live with this. The next one will support element types that are merely movable. That is, a moved object does not need to be equal to the object moved to. That will allow putting streams, transfer-of-ownership pointers and threads into containers.

See what the Standard says for this (17.4.3.6):

In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard Library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

In particular, the effects are undefined in the following cases:

  • for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause (20.1.5, 23.1, 24.1, 26.1).
北凤男飞 2024-07-23 16:56:43

我已经发布了一个问题作为后续问题
对于这个答案,请参阅
包含存储在向量中的 auto_ptr 的类

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

尽管不太可能,但您确实可能想要这种行为,在这种情况下 auto_ptr 是安全的。 假设您不这样做,您应该:

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

注意这还不够 - 请参阅上面提到的后续问题以获取更多信息。

或者:

  • 使用更智能的,可能的参考计数指针,例如 boost 智能指针之一

I've posted a question as a follow-up
to this answer, see
Class containing auto_ptr stored in vector.

Assming your class does not have a user-defined copy constructor, then no, it is probably (see below) not safe. When your class is copied (as will happen when it is added to a vector) the copy constructor of the auto_ptr will be used. This has the weird behaviour of tranferring ownership of the thing being copied to the copy and, so the thing being copied's pointer is now null.

It is possible, though unlikely, that you actually want this behaviour, in which case an auto_ptr is safe. Assuming you do not, you should either:

  • add a copy constructor to manage the copying

Note this is not enough - see the follow-up question mentioned above for more info.

or:

  • use a smarter, possibly reference counted pointer, such as one of the boost smart pointers
娇纵 2024-07-23 16:56:43

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

Copying MyClass object will cause either call to assignment operator or copy constructor. If they are not overloaded to handle auto_ptr<> in unusual way, they will propagate the call to copy constructor (or assignment operator) to the auto_ptr<> member. This may lead to problems described in question you had linked.

北渚 2024-07-23 16:56:43

实例化 auto_pointer 向量不安全的原因是有一种算法:sort(),它将在堆栈上的容器中复制一个对象。 (sort() 实现了需要“枢轴”的快速排序)
因此,当超出 sort() 函数的范围时将其删除。
同样,任何能够将容器作为参数并在堆栈上复制其对象之一的算法或您自己的函数都会导致此问题。

就您而言,很简单,您必须确保您的类不会表现为 auto_ptr,或者确保您永远不会调用此类可以删除底层对象的函数/算法。 根据我的说法,第一个解决方案是最好的:)

因此,您的复制构造函数和影响运算符不应放弃指针对象的属性。

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

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

The reason why it is not safe to instanciate a vector of auto_pointer is that there is an algorithm : sort(), that will do a copy of one object in your container on the stack. (sort() implements quicksort which needs a "pivot")
And therefore deleting it when going out of scpope of the sort() function.
As well any algorithm, or function of your own that are able to take your container as parameter, and copy one of its object on the stack will cause this issue as a result.

Well in your case, it is simple you must ensure your class does not behaves as an auto_ptr, or ensure you will never call such function/algorithm that can delete your underlying objects. The first solution is best, according to me :)

So your copy constructor and your affectation operator as well, should not give away property of the pointer object.

The best way to achieve that is to wrapp a boost smart pointer instead of an auto_ptr, to make your container safe when calling such function/algorithm.

By the way according to me, defining a better copy constructor/affectation operator to bypass this issue is not a good solution: I can't see a good copy constructor implementation (and affectation operator as well) that could keep safe the result of applying the sort() algorithm.

岁月无声 2024-07-23 16:56:43

如果你想在容器中使用一个使用 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 配合良好,您也会面临发现另一个实现不起作用的风险。 该标准仅保证性能和可观察的行为,而不是实施。

If you want to use a class that uses auto_ptr in a container, you can just provide a copy-constructor and assignment operator yourself:

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

But as mentioned elsewhere, the standard lets containers make copies and assignments and assumes that the contained classes will behave in a specific manner that auto_ptr violates. By defining the methods above, you can make a class that contains an auto_ptr behave. Even if your implementation works fine with auto_ptrs, you run the risk of finding another implementation doesn't work. The standard only make guarantees of performance and observable behaviour, not implementation.

江湖正好 2024-07-23 16:56:43

不起作用。 auto_ptr 不计算引用,这意味着在第一次析构函数调用时,您的指针将被释放。

使用 boost::shared_ptr 代替。

It will not work. auto_ptr doesn't count references which means at the first destructor call your pointer will be freed.

Use boost::shared_ptr instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文