use*_*498 12 c++ reference placement-new c++11
我知道通常在初始化之后重置参考是不可能的.
但是,我以某种方式尝试以下代码,它恰好适用于clang ++和g ++.
我的问题是,以下是一个有效的(行为定义的)C++?
std::string x = "x";
std::string y = "y";
std::string i = "i";
std::string j = "j";
// now references to x, y
std::pair<std::string &, std::string &> p { x, y };
p.first = "1"; //changes x
p.second = "2"; //changes y
// now references to i, j
new (&p) std::pair<std::string &, std::string &> {i, j};
p.first = "1"; //changes i
p.second = "2"; //changes j
Run Code Online (Sandbox Code Playgroud)
上面的代码适用于g ++和clang ++,但它是不是很好的C++?谢谢.
Pas*_* By 23
该片段具有未定义的行为,但几乎没有.从概念上讲,您销毁了旧引用并创建了新引用,即使重用了内存,也没有重新引用引用.这部分完全没问题.
catch是如果重用的类包含const或引用成员,那么变量的原始名称不能用于引用新对象
new (&p) std::pair<std::string &, std::string &> {i, j};
// p does not refer to the newly constructed object
p.first = "1"; // UB
p.second = "2"; // UB
Run Code Online (Sandbox Code Playgroud)
在这种情况下,修复很简单
auto p2 = new (&p) std::pair<std::string&, std::string&> {i, j};
p2->first = "1";
p2->second = "2";
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是C++ 17功能 std::launder
new (&p) std::pair<std::string &, std::string &> {i, j};
std::launder(&p)->first = "1";
std::launder(&p)->second = "2";
Run Code Online (Sandbox Code Playgroud)
这些规则可能使编译器能够围绕引用和const成员进行更多优化.
Sto*_*ica 20
我的问题是,以下是一个有效的(行为定义的)C++?
它可能是.这里的关键是那对.您结束了对对象的生命周期,并在同一存储中启动了另一对对象的生命周期(placement new会同时执行这两项操作).
但是你应该知道你没有重新引用任何引用.你杀了一个持有引用的对象,并在同一个地方创建一个新的.从概念上讲,你有两个"旧"引用,现在有两个"新"引用.
你的代码可以很好,因为该对是一个包含一对引用的简单结构,如果该对保持任何简单的可破坏类型,它将是有效的.但是,如果任何对元素的d'tor不是微不足道的,那么你将有未定义的行为.因为析构函数不会作为放置新的一部分执行.
Passer注意到的问题是,你不能p用来引用"新对象",因为它包含引用.这将是UB的原因.
它是好的C++?
这是值得商榷的.这当然不是人们期望经常看到的.