包含存储在向量中的 auto_ptr 的类

发布于 2024-07-16 03:03:37 字数 1236 浏览 2 评论 0原文

在对 将具有 std::auto_ptr 作为其成员变量的类的对象存储在 std::vector 中是否安全? 我说过包含 auto_ptr 的类可以存储在向量前提是该类具有用户定义的复制构造函数

有一些评论表明情况并非如此,因此这个问题是试图澄清问题。 考虑以下代码:

#include <memory>
#include <vector>
using namespace std;

struct Z {};

struct A {

    A( Z z ) 
        : p( new Z(z) ) {} 

    A( const A & a ) 
        : p( a.p.get() ? new Z( *a.p.get()) : 0 ) {}

    // no assigment op or dtor defined by intent

    auto_ptr <Z> p;
};

int main() {
    vector <A> av;              
    Z z;                    
    A a(z);
    av.push_back( a );      
    av.push_back( A(z) );   
    av.clear();             
}                           

请检查上面的& 在您的回复中指出未定义的地方 对于以这种特定方式使用的特定类,可能会出现 C++ 标准含义中的行为。 我不感兴趣这个类是否有用、行为良好、可排序,或者它在异常情况下的表现如何。

另请注意,这不是关于创建 auto_ptrs 向量的有效性的问题 - 我很清楚与此相关的问题。

感谢大家的意见 回顾过去可能是相当愚蠢的 问题。 我想我太专注了 关于复制者和 忘记了 任务。 我的幸运获奖者 接受分数(分数意味着 奖品!)对于典型的litb 详尽的解释(抱歉 耳柳克)

In an answer to Is it safe to store objects of a class which has an std::auto_ptr as its member variable in std::vector? I stated that a class that contained an auto_ptr could be stored in a vector provided the class had a user-defined copy constructor.

There were several comment suggesting that this was not the case, so this question is an attempt to clear the issue up. Consider the following code:

#include <memory>
#include <vector>
using namespace std;

struct Z {};

struct A {

    A( Z z ) 
        : p( new Z(z) ) {} 

    A( const A & a ) 
        : p( a.p.get() ? new Z( *a.p.get()) : 0 ) {}

    // no assigment op or dtor defined by intent

    auto_ptr <Z> p;
};

int main() {
    vector <A> av;              
    Z z;                    
    A a(z);
    av.push_back( a );      
    av.push_back( A(z) );   
    av.clear();             
}                           

Please examine the above & in your reply indicate where undefined
behaviour in the meaning of the C++ Standard could occur for this particular class used in this particular way. I am not interested whether the class is useful, well-behaved, sortable, or how it performs under exceptions.

Please also note that this is not a question about the validity of creating a vector of auto_ptrs - I am well aware of the issues regarding that.

Thanks all for your inputs on what in
retrospect is probably a rather silly
question. I guess I focussed too much
on the copy ctor & forgot about
assignment. The lucky winner of my
acceptance points (and points mean
prizes!) is litb for a typically
exhaustive explanation (sorry
earwicker)

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

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

发布评论

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

评论(5

-残月青衣踏尘吟 2024-07-23 03:03:37

存储在容器中的对象需要“可复制构造”和“可分配”(C++2008 23.1/3)。

你的类尝试处理 CopyConstructable 要求(尽管我认为它仍然不满足它 - 我编辑了该参数,因为它不是必需的,而且我想它是有争议的),但它不处理可分配的要求。 要可分配 (C++2008 23.1/4),必须满足以下条件,其中 tT 的值,u 是值(可能是 constT

t = u 返回 T& 并且 t 相当于 u

该标准还在注释中说(20.4 .5/3):“auto_ptr 不满足标准库容器元素的可复制构造和可分配要求,因此使用 auto_ptr 实例化标准库容器会导致未定义的行为。 ”

由于您没有声明或定义赋值运算符,因此将提供一个使用 auto_ptr 的赋值运算符的隐式赋值运算符,这肯定使得 t 不等于 u,更不用说它对于“const T u”值根本不起作用(这就是Earwicker 的回答 指出 - 我只是指出标准的确切部分)。

Objects stored in containers are required to be "CopyConstructable" as well as "Assignable" (C++2008 23.1/3).

Your class tries to deal with the CopyConstructable requirement (though I'd argue it still doesn't meet it - I edited that argument out since it's not required and because it's arguable I suppose), but it doesn't deal with the Assignable requirement. To be Assignable (C++2008 23.1/4), the following must be true where t is a value of T and u is a value of (possibly const) T:

t = u returns a T& and t is equivalent to u

The standard also says in a note (20.4.5/3): "auto_ptr does not meet the CopyConstructible and Assignable requirements for Standard Library container elements and thus instantiating a Standard Library container with an auto_ptr results in undefined behavior."

Since you don't declare or define an assignment operator, an implicit one will be provided that uses the auto_ptr's assignment operator, which definitely makes t not equivalent to u, not to mention that it won't work at all for "const T u" values (which is what Earwicker's answer points out - I'm just pointing out the exact portion(s) of the standard).

追风人 2024-07-23 03:03:37

尝试将位置列表放在一起,这会导致示例出现未定义的行为。

#include <memory>
#include <vector>
using namespace std;

struct Z {};

struct A {

    A( Z z ) 
        : p( new Z(z) ) {} 

    A( const A & a ) 
        : p( a.p.get() ? new Z( *a.p.get()) : 0 ) {}

    // no assigment op or dtor defined by intent

    auto_ptr <Z> p;
};

int main() {
    vector <A> av;  
    ...
}

我将检查直到使用类型 A 实例化向量的那一行。 规定

标准在 23.1/3

存储在这些组件中的对象类型必须满足 CopyConstructible 类型 (20.1.3) 的要求,以及可分配类型的附加要求。

23.1/4 中(强调我的):

在表 64 中,T 是用于实例化容器的类型,t 是 T 的值,u 是(可能是 const)T 的值。

<前><代码>+------------+----------------+---------------- ------+
|表达式 |返回类型 |后置条件 |
+------------+----------------+-------------------- +
|t = u |T& |t 等于 u |
+------------+----------------+-------------------- +

表64

12.8/10< /代码>:

如果类定义没有显式声明复制赋值运算符,则隐式声明一个。 类 X 的隐式声明的复制赋值运算符将具有以下形式

X&   X::运算符=(const X&) 
  

如果

  • X 的每个直接基类 B 都有一个复制赋值运算符,其参数类型为 const B&,
    const 易失性 B& 或B,并且
  • 对于 X 中属于类类型 M(或其数组)的所有非静态数据成员,每个此类类类型都有一个复制赋值运算符,其参数类型为 const M&、const volatile M& 和 const M&。 或M。

否则,隐式声明的复制赋值运算符将具有以下形式

X&   X::运算符=(X&) 
  

(注意最后一句和倒数第二句)

17.4.3.6/1 和 /2 中:

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

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

  • 对于实例化模板组件时用作模板参数的类型,如果类型上的操作未实现适用的要求子条款(20.1.5、23.1、24.1、26.1)的语义。 除非另有说明,否则对此类类型的操作可以通过抛出异常来报告失败。

现在,如果您查看 auto_ptr 的规范,您会注意到它有一个接受非常量 auto_ptr 的复制赋值运算符。 因此,类的隐式声明的复制赋值运算符也将采用非常量类型作为其参数。 如果你仔细阅读上面的地方,你会看到它是如何说用你所写的类型实例化一个向量是未定义的行为。

Trying to put the list of places together that makes the example undefined behavior.

#include <memory>
#include <vector>
using namespace std;

struct Z {};

struct A {

    A( Z z ) 
        : p( new Z(z) ) {} 

    A( const A & a ) 
        : p( a.p.get() ? new Z( *a.p.get()) : 0 ) {}

    // no assigment op or dtor defined by intent

    auto_ptr <Z> p;
};

int main() {
    vector <A> av;  
    ...
}

I will examine the lines up to the one where you instantiate the vector with your type A. The Standard has to say

In 23.1/3:

The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignable types.

In 23.1/4 (emphasis mine):

In Table 64, T is the type used to instantiate the container, t is a value of T, and u is a value of (possibly const) T.

+-----------+---------------+---------------------+
|expression |return type    |postcondition        |
+-----------+---------------+---------------------+
|t = u      |T&             |t is equivalent to u |
+-----------+---------------+---------------------+

Table 64

In 12.8/10:

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. The implicitly-declared copy assignment operator for a class X will have the form

X& X::operator=(const X&)

if

  • each direct base class B of X has a copy assignment operator whose parameter is of type const B&,
    const volatile B& or B, and
  • for all the nonstatic data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.

Otherwise, the implicitly declared copy assignment operator will have the form

X& X::operator=(X&)

(Note the last and second last sentence)

In 17.4.3.6/1 and /2:

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). Operations on such types can report a failure by throwing an exception unless otherwise specified.

Now, if you look at the specification of auto_ptr you will note it has a copy-assignment operator that takes a non-const auto_ptr. Thus, the implicitly declared copy assignment operator of your class will also take a non-const type as its parameter. If you read the above places carefully, you will see how it says that instantiating a vector with your type as written is undefined behavior.

栀子花开つ 2024-07-23 03:03:37

我认为上面的代码不一定能编译。 当然,std::vector 的实现者可以自由地要求来自 const A& 的赋值运算符可用吗?

刚刚尝试过,它无法在 Visual Studio C++ 2008 Service Pack 1 上编译:

二进制“=”:没有找到哪个运算符
接受类型的右侧操作数
'const A'(或者没有可接受的
转换)

是,在 Herb Sutter 的指导下,VC++ 中的容器类尽一切努力对其类型参数强加标准要求,特别是使 auto_ptr 与它们一起使用变得困难。 当然,它们可能超越了标准设定的界限,但我似乎记得它要求真正的赋值以及真正的副本构造。

然而,它确实可以在 g++ 3.4.5 中编译。

I don't think it's necessarily the case that the above code will even compile. Surely the implementor of std::vector is at liberty to require an assignment operator to be available, from const A&?

And having just tried it, it doesn't compile on Visual Studio C++ 2008 Service Pack 1:

binary '=' : no operator found which
takes a right-hand operand of type
'const A' (or there is no acceptable
conversion)

My guess is that, on the guidance of Herb Sutter, the container classes in VC++ make every effort to impose the standard requirements on their type parameters, specifically to make it hard to use auto_ptr with them. They may have overstepped the boundaries set by the standard of course, but I seem to remember it mandating true assignment as well as true copy construction.

It does compile in g++ 3.4.5, however.

我是有多爱你 2024-07-23 03:03:37

由于常规 auto_ptr 语义可能表明所有权在复制过程中传递,因此我宁愿在这里使用 boost::scoped_ptr。 当然缺少赋值运算符。

Since the regular auto_ptr semantic could suggests that the ownership is passed during the copying, I would rather use here boost::scoped_ptr. Of course the assignment operator is missing.

°如果伤别离去 2024-07-23 03:03:37

那么下面的呢?

cout << av[ 0 ] << endl;

另外,从概念上讲,副本应该使复制的项目保持不变。 您的实施中违反了这一点。

(你的原始代码可以用 g++ -pedantic ... 和 Comeau 编译良好,但不能用 VS2005 编译,这是另一回事。)

What about the following?

cout << av[ 0 ] << endl;

Also, conceptually, a copy should leave the item copied from unchanged. This is being violated in your implementation.

(It is quite another thing that your original code compiles fine with g++ -pedantic ... and Comeau but not VS2005.)

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