spr*_*aff 8 c++ const reference placement-new c++11
以下代码是允许
struct Foo {
int x;
};
Foo f;
Foo & f_ref = f;
(&f) -> ~Foo ();
new (&f) Foo ();
int x = f_ref .x;
Run Code Online (Sandbox Code Playgroud)
但下面的代码是不容许
struct Foo {
const int & x; // difference is const reference
Foo (int & i) : x(i) {}
};
int i;
Foo f (i);
Foo & f_ref = f;
(&f) -> ~Foo ();
new (&f) Foo (i);
int x = f_ref .x;
Run Code Online (Sandbox Code Playgroud)
因为3.8美元/ 7
如果在对象的生命周期结束之后并且在重用或释放对象占用的存储之前,则在原始对象占用的存储位置创建新对象,指向原始对象的指针,引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用来操纵新对象,如果:
- 原始对象的类型不是const-quali fi ed,如果是类类型,则不包含任何类型为const-quali的非静态数据成员或引用类型 ...
我可以理解f.x当f不再存在时如何使引用无效,但我不明白为什么它f_ref应该被无效纯粹因为它的一个成员是const和/或引用而不是其他:它是对a Foo之前的引用和是Foo后来的参考.
有人可以解释这种情况背后的理由吗?
谢谢你的回答.我不买了"保证它不会改变"的说法,因为我们没有目前允许优化器缓存referands,例如:
struct Foo {
const int & x;
Foo (const int & i) : x(i) {}
void do_it ();
};
int i;
Foo f (i);
const int & ii = f.x;
f .do_it (); // may modify i
std :: cout << ii; // May NOT use cached i
Run Code Online (Sandbox Code Playgroud)
我没有看到如何do_it使引用值无效但operator new不是 - 序列点使缓存值无效:为什么要删除/ placement-new是免除的?
我相信动机是允许编译器缓存const对象的值(注意const 对象,而不仅仅是指向const和引用到const的指针),以及引用的referands地址,以及对未知的调用码.
在第二个示例中,编译器可以首先"看到"对象已被创建和销毁,其次是使用相同的值重新创建.但该标准的作者希望允许编译器转换此代码:
struct Foo {
const int & x;
Foo (int & i) : x(i) {}
};
int i = 1;
Foo f(i);
some_function_in_another_TU(&f);
std::cout << f.x;
Run Code Online (Sandbox Code Playgroud)
进入:
struct Foo {
const int & x;
Foo (int & i) : x(i) {}
};
int i = 1;
Foo f(i);
some_function_in_another_TU(&f);
std::cout << i; // this line is optimized
Run Code Online (Sandbox Code Playgroud)
因为参考成员f不能重新安置,因此必须参考i.destruct-and-construct操作违反了引用成员的不可重用性x.
这种优化不应该特别引起争议:考虑以下示例,使用const对象而不是具有const或引用成员的对象:
const int i = 1;
some_function_in_another_TU(&i);
std::cout << i;
Run Code Online (Sandbox Code Playgroud)
这i是一个编译时常量,some_function_in_another_TU无法有效地销毁它并int使用不同的值在其位置创建另一个.所以应该允许编译器发出代码std::cout << 1;.想法是,对于其他类型的const对象和引用,类似应该是真的.
如果对未知代码的调用可能会重新引用引用成员,或者更改const数据成员的值,那么语言的有用不变量(引用永远不会被重置,而const对象永远不会更改它们的值)将被破坏.
据我所知,这只是语义正确性以及优化器可能做出的附加假设.考虑一下:
Bar important, relevant;
Foo x(important); // binds as const-reference
Zoo z(x); // also binds as const reference
do_stuff(z);
x.~Foo();
::new (&x) Foo(relevant); // Ouch?
Run Code Online (Sandbox Code Playgroud)
该对象z可以合理地期望其Foo成员引用是恒定的并且因此参考important.正如标准所说,最后两行中的破坏加上新构造"自动更新所有引用以引用(逻辑上)新对象",所以现在const-reference内部z已经改变,尽管有希望保持不变.
为了避免这种违反正常性的背叛行为,禁止整个原地重建.