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