为什么语句“vector<int>(v1);”会失败?

6

vector<int>(v1)表达式会产生一个临时对象,可以放在operator=的右边,但如果我们将vector<int>(v1)表达式用作语句,在Visual Studio 2010 10.0.30319.1 RTMRel中会失败。以下代码中的注释提供了详细的错误信息。为什么会发生这种情况呢?

vector<int> v1; 
v1.push_back( 10 );
v1.push_back( 20 );
v1.push_back( 30 );    
vector<int> v3 = vector<int>(v1);  //OK, deliberately code like this.
vector<int>(v1);  //error C2086: “std::vector<_Ty> v1”: redefinition

在书籍《C++编码规范:101条规则、指南和最佳实践》的第82章“使用已被接受的习语来真正缩小容量并真正删除元素”。其中有一句话:
container<_Type>(c).swap(c);

我不理解,只是想测试container<_Type>(c),这是什么意思?

请在代码行前使用四个空格来标记它们为代码,并添加换行符(对于将来的帖子,请参考@Yu Hao已经编辑过的当前帖子)。 - Thomas
如果我们将vector(v1)表达式用作语句,[它会失败] -- 好的,但是你为什么想要这样做呢?你想要实现什么目标? - Brian Cain
你为什么认为这是一个有效的陈述?你期望它会产生什么影响? - kfsone
1
这是歧义解决的结果。如果一个结构可以被解析为声明,那么它就是一个声明。 - sp2danny
3个回答

6

vector<int>(v1);vector<int> v1;是相同的,即变量重新定义。


1
这些奇怪的括号之所以存在,是因为在更复杂的情况下需要它们,比如 std::vector<int> (*pFunc)(std::list<int>)。这里的 *pFunc 相关,而不是与 std::vector<int> 相关。 - MSalters

4

vector<int>(v1) 表达式产生一个临时对象,可以放在 operator= 的右边,但如果我们将 vector<int>(v1) 表达式作为语句使用,则会失败...

编译器对于普通语句的处理方式不同:

vector<int>(v1); //error C2086: “std::vector<_Ty> v1”: redefinition

这是一种替代的编写方式

vector<int> v1;

如果您重新定义v1,编译器会发出警告。


为了查看您的临时初始化工作,请使用以下示例:

void foo(const std::vector<int>& v)
{
}

并调用
foo(vector<int>(v1));

或者简单来说1
(std::vector<int>)(v1); // this creates a temporary which is immediately disposed

点击查看后一部分的实时演示


1)源自@Sergey A答案,但他更喜欢删除它。


1
我知道vector<int>(v1)这种写法可能让人感到不直观,但是我并没有看出使用它的意义。正如其他人所指出的那样,这是标准行为。如果您正在寻找解决方案,这里有两个解决方法:
vector<int>::vector( v1 );
vector<int> { v1 };

编辑(问题已更改):"container<_Type>(c).swap(c); 我不明白..." 这与 container<_Type>(c); 不同。容器的容量可能比通过 size 报告的容量要大(请参见 reserve)。保留有助于最小化某些操作的数量。如果添加一个新元素,容器将使用已分配的内存。例如,您的 vector 可能有 10 个元素的空间,但实际上只有 1 个。如果添加一个新元素,将剩下 8 个元素的空间。上述结构移除了保留以节省内存。首先制作原始副本(此副本没有保留)。然后,用新的数据(指针)替换原始向量的底层数据(请参见 swap),并丢弃临时对象(现在拥有原始内存的对象)。

"...测试container<_Type>(c)是什么意思?" 在上述用法中,它的意思是"创建c的临时副本"。在孤立使用时,它看起来像一个复制构造函数,但实际上它声明了一个对象。区别由点运算符给出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接