struct C{
std::vector<int> foo;
const int &bar;
C();
};
C::C(): bar(foo[0]){
foo.push_back(5);
}
代码可以编译,但编译后的文件无法运行。
这种初始化参考条的方法有什么问题?我认为只要foo在bar之前声明,我们可以使用foo [0]来初始化构造函数中的bar吗?
任何人都可以提出任何想法,为什么会出现这种情况?
答案 0 :(得分:0)
你的矢量处于空状态。初始化列表在括号中的代码之前构造对象,因此push_back
不会影响bar(foo[0])
。所以你的foo[0]
正在访问一个空的向量并且超出范围。
请注意,每当调整大小时,对vector
元素的引用都会失效。所以保持对vector元素的引用是不值得的。
答案 1 :(得分:0)
因为你的foo是未初始化的,所以你可以使用初始化列表初始化你的foo,其大小至少为1之前的bar。这也是c ++ 98有效。
struct C{
std::vector<int> foo;
const int &bar;
C();
};
C::C() : foo(1) // initialize foo with size 1
, bar(foo[0]) {
foo[0]=5; // this is guarateed to be exception safe
}
但您必须注意初始化列表顺序。它按结构/类中的声明顺序排序。见here
根据ISO / IEC 14882:2003(E)第12.6.2节:
初始化应按以下顺序进行:
- 首先,仅对于如下所述的派生类最多的构造函数,虚拟基类应按它们出现在基类有向无环图的深度优先从左到右遍历的顺序进行初始化,其中“从左到右”是派生类base-specifier-list中基类名称的出现顺序。
- 然后,直接基类应按声明顺序初始化,因为它们出现在base-specifier-list中(无论mem-initializers的顺序如何)。
- 然后,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。
- 最后,执行构造函数的主体。
感谢 Kerrek SB 的评论,你不能使用你的矢量。当你推送一些东西时,foo将被调整大小(重新分配)并且bar将失去正确的引用。你可以使用std::deque
或者将向量初始化为一个永远不会传递的特定大小。