C++ 类,该类包含存储在vector中的auto_ptr
在对我的回答中,我指出,如果类具有用户定义的复制构造函数,则包含auto_ptr的类可以存储在向量中 有几条评论认为情况并非如此,因此这个问题旨在澄清问题。考虑下面的代码:C++ 类,该类包含存储在vector中的auto_ptr,c++,stl,C++,Stl,在对我的回答中,我指出,如果类具有用户定义的复制构造函数,则包含auto_ptr的类可以存储在向量中 有几条评论认为情况并非如此,因此这个问题旨在澄清问题。考虑下面的代码: #include <memory> #include <vector> using namespace std; struct Z {}; struct A { A( Z z ) : p( new Z(z) ) {} A( const A & a )
#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();
}
#包括
#包括
使用名称空间std;
结构Z{};
结构A{
A(Z)
:p(新Z(Z)){}
A(常数A&A)
:p(a.p.get()?新Z(*a.p.get()):0){
//没有意图定义的分配op或dtor
自动ptr p;
};
int main(){
向量av;
Z Z;
A(z);
av.推回(a);
平均推回(A(z));
av.clear();
}
请检查以上内容&在您的回复中指出未定义的位置
C++标准的含义可以在这个特定的方式中使用。我不关心这个类是否有用、行为良好、可排序,也不关心它在异常情况下如何执行
请注意,这不是一个关于创建自动PTR向量的有效性的问题-我很清楚与此相关的问题。
感谢大家对本项目的投入
回顾可能是一个相当愚蠢的问题
问题。我想我太专注了
在副本上&忘记了
分配幸运的获胜者
验收点(和平均值)
奖品!)是一种典型的
详尽的解释(对不起
(耳塞)
由于常规的
auto_ptr
语义可能表明所有权在复制过程中传递,因此我宁愿在这里使用boost::scoped_ptr
。当然,赋值运算符丢失了。我认为上面的代码不一定会编译。当然,std::vector
的实现者可以自由地要求从const A&
提供赋值运算符
并且刚刚尝试过,它没有在VisualStudioC++ 2008 Service PACK 1上编译:
二进制“=”:未找到 接受类型为的右侧操作数 “常数A”(或不可接受) 转换) 我的猜测是,在Herb Sutter的指导下,VC++中的容器类尽一切努力将标准要求强加给它们的类型参数,特别是使它们难以使用auto_ptr
。当然,他们可能已经超越了标准所规定的界限,但我似乎记得它要求真正的任务以及真正的副本构建
但是,它确实是在g++3.4.5中编译的。下面是什么
cout << av[ 0 ] << endl;
cout存储在容器中的对象要求是“可复制的”和“可分配的”(C++2008 23.1/3)
您的类尝试处理CopyConstructable需求(尽管我认为它仍然不满足它-我编辑了该参数,因为它不是必需的,并且我认为它是可论证的),但它不处理可分配的需求。要可赋值(C++2008 23.1/4),以下内容必须为真,其中t
是t
的值,u
是(可能const
)t
:
t=u
返回一个t&
,t
相当于u
该标准还在注释(20.4.5/3)中指出:“auto_ptr
不满足标准库容器元素的可复制和可分配要求,因此使用auto_ptr
实例化标准库容器会导致未定义的行为。”
由于您没有声明或定义赋值运算符,因此将提供一个使用auto_ptr
赋值运算符的隐式赋值运算符,这肯定会使t
不等同于u
,更不用说它对“const t u
”值根本不起作用(这就是我所指出的——我只是指出标准的确切部分)。试图将使示例行为未定义的位置列表放在一起
#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;
...
}
表64
在12.8/10
中:
如果类定义没有显式声明复制赋值运算符,则隐式声明一个。类X的隐式声明复制赋值运算符的形式为
X& X::operator=(const X&)
X& X::operator=(X&)
如果
- X的每个直接基类B都有一个复制赋值运算符,其参数类型为const B&,
常量挥发性食宿,以及
- 对于类类型为M(或其数组)的X的所有非静态数据成员,每个此类类类型都有一个复制赋值运算符,其参数类型为const M&,const volatile M&或M
否则,隐式声明的复制赋值运算符将具有
X& X::operator=(const X&)
X& X::operator=(X&)
(注意最后一句和第二句)
在17.4.3.6/1和/2中
:
在某些情况下(替换函数、处理函数、用于实例化标准库模板组件的类型的操作),C++标准库依赖于C++程序提供的组件。如果这些组件不符合它们的要求,则标准不要求实现。
特别是,在以下情况下,影响未定义:
- 对于实例化模板组件时用作模板参数的类型,如果该类型上的操作未实现适用需求子类(20.1.5、23.1、24.1、26.1)的语义。除非另有规定,否则此类类型上的操作可以通过引发异常来报告失败
现在,如果您查看auto_ptr
的规范,您会注意到它有一个复制赋值操作符,它接受一个非常量auto_ptr