我有以下代码,其中我有成员 v _ ,一个const 引用向量的向量。它用左值初始化,所以我的 思考是不应该造成任何副本。
#include <iostream>
#include <iterator>
#include <vector>
using Vec = std::vector<int>;
void out(Vec const& v) {
using namespace std;
cout << "Vector (" << &v[0] << "): [";
ostream_iterator<int> out_it (cout,", ");
copy(v.begin(), v.end(), out_it);
cout << "]\n";
}
struct V {
V(Vec const& v) : v_{v}{}
Vec const& v_;
};
int main(int argc, char** argv) {
Vec v = { 1, 2, 3, 4, 5 };
out(v);
V wrapped { v };
out(wrapped.v_);
}
使用 clang版本3.6.0(主干225298),我得到以下输出:
~/tmp$ clang++ -std=c++11 -g -O0 vecmember.cpp
~/tmp$ ./a.out
Vector (0x2480010): [1, 2, 3, 4, 5, ]
Vector (0x2480010): [1, 2, 3, 4, 5, ]
这是我所希望的。 但是,使用 c ++(Ubuntu 4.8.2-19ubuntu1)4.8.2 ,我得到以下输出:
~/tmp$ c++ -std=c++11 -g -O0 vecmember.cpp
~/tmp$ ./a.out
Vector (0xa58010): [1, 2, 3, 4, 5, ]
Vector (0xa58030): []
当我进入调试器时,它会进入 stl_vector.h 函数向量(const vector&amp; __x),所以它试图复制构造传递给它的原始向量构造函数。这是一个编译器错误还是我以某种方式做了一些未定义或完全错误的事情?
在任何一种情况下,什么是更好的方法?
答案 0 :(得分:2)
C ++ 11标准实际上说当你列出初始化这样的引用时:
int i;
int & ir{i};
它构造一个临时的,然后绑定对临时的引用。 (在上面的例子中,它会失败,因为非const值左值引用不能绑定到临时值。)
显然,这绝对没有任何意义;这是标准的缺陷。不幸的是,GCC 4.8在这封信中实现了这部分标准,至少在构造函数的成员初始化列表中。因此,v_{v}
构造了一个临时std::vector
并将其临时绑定到v_
(绑定成功,因为v_
是一个const引用);临时结束的生命周期结束于构造函数的末尾,引用变为悬空,这意味着您的第二个out
调用具有未定义的行为。
标准缺陷由CWG issue 1288的解决方案确定,此修订在GCC 4.9中实施(请参阅GCC bug 50025)。如果您遇到GCC 4.8,解决方法是使用旧的初始化语法v_(v)
。