【问题标题】:const& vector member initialized with const& vector in ctor用 ctor 中的 const 向量初始化的 const 向量成员
【发布时间】:2015-01-27 02:43:14
【问题描述】:

我有以下代码,其中我有成员 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 (trunk 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 函数 vector(const vector& __x) 所以它试图复制构造传递给构造函数的原始向量.这是一个编译器错误还是我以某种方式做了一些未定义或完全错误的事情?

在这两种情况下,有什么更好的方法?

【问题讨论】:

  • 列表初始化和引用的标准存在缺陷。 GCC 4.8 不折不扣地实现了标准(包括缺陷)。标准缺陷后来被修复,GCC 4.9 实现了修复。
  • @T.C.是的,这就是答案,想把它写成一个吗? :)

标签: c++ c++11 vector reference constants


【解决方案1】:

C++11 标准实际上是这样说的,当你列出初始化一个引用时:

int i;
int & ir{i};

它构造一个临时对象,然后将引用绑定到该临时对象。 (在上面的示例中,它会失败,因为非常量左值引用不能绑定到临时对象。)

显然,这绝对没有任何意义;这是标准中的缺陷。不幸的是,GCC 4.8 实现了这部分标准,至少在构造函数的成员初始化列表中。结果,v_{v} 构造了一个临时的std::vector 并将该临时绑定到v_(绑定成功,因为v_ 是一个常量引用);临时对象的生命周期在构造函数结束时结束,并且引用变得悬空,这意味着您的第二个 out 调用具有未定义的行为。

标准缺陷已由CWG issue 1288 的分辨率修复,此修复已在 GCC 4.9 中实现(请参阅GCC bug 50025)。如果您使用 GCC 4.8,解决方法是使用旧的初始化语法 v_(v)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2014-09-08
    • 2016-12-02
    • 2015-01-21
    • 2012-10-03
    • 2012-12-15
    • 2013-01-07
    相关资源
    最近更新 更多