包含存储在向量中的 auto_ptr 的类
在对 将具有 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
存储在容器中的对象需要“可复制构造”和“可分配”(C++2008 23.1/3)。
你的类尝试处理 CopyConstructable 要求(尽管我认为它仍然不满足它 - 我编辑了该参数,因为它不是必需的,而且我想它是有争议的),但它不处理可分配的要求。 要可分配 (C++2008 23.1/4),必须满足以下条件,其中
t
是T
的值,u
是值(可能是const
)T
:该标准还在注释中说(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 ofT
andu
is a value of (possiblyconst
)T
: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 anauto_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 makest
not equivalent tou
, 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).尝试将位置列表放在一起,这会导致示例出现未定义的行为。
我将检查直到使用类型
A
实例化向量的那一行。 规定标准在
23.1/3
中在
23.1/4
中(强调我的):在
12.8/10< /代码>:
(注意最后一句和倒数第二句)
在
17.4.3.6/1 和 /2
中:现在,如果您查看
auto_ptr
的规范,您会注意到它有一个接受非常量auto_ptr
的复制赋值运算符。 因此,类的隐式声明的复制赋值运算符也将采用非常量类型作为其参数。 如果你仔细阅读上面的地方,你会看到它是如何说用你所写的类型实例化一个向量是未定义的行为。Trying to put the list of places together that makes the example undefined behavior.
I will examine the lines up to the one where you instantiate the vector with your type
A
. The Standard has to sayIn
23.1/3
:In
23.1/4
(emphasis mine):In
12.8/10
:(Note the last and second last sentence)
In
17.4.3.6/1 and /2
:Now, if you look at the specification of
auto_ptr
you will note it has a copy-assignment operator that takes a non-constauto_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.我认为上面的代码不一定能编译。 当然,
std::vector
的实现者可以自由地要求来自const A&
的赋值运算符可用吗?刚刚尝试过,它无法在 Visual Studio C++ 2008 Service Pack 1 上编译:
是,在 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, fromconst A&
?And having just tried it, it doesn't compile on Visual Studio C++ 2008 Service Pack 1:
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.
由于常规
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 hereboost::scoped_ptr
. Of course the assignment operator is missing.那么下面的呢?
另外,从概念上讲,副本应该使复制的项目保持不变。 您的实施中违反了这一点。
(你的原始代码可以用
g++ -pedantic ...
和 Comeau 编译良好,但不能用 VS2005 编译,这是另一回事。)What about the following?
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.)