【问题标题】:Is it defined behavior to use placement new to change type of variable that is held by reference_wrapper?使用placement new 更改reference_wrapper 持有的变量类型是否已定义行为?
【发布时间】:2017-07-15 19:53:02
【问题描述】:

我搞砸了新的位置,并制作了以下代码:

#include <iostream>
#include <functional>
#include <new>

int main()
{
    char memory[sizeof(int)]; //memory to hold type
    auto ref = std::ref(*new (memory) int{5}); //allocating int in memory, and make a reference to it
    std::cout << ref << std::endl;
    new (memory) unsigned{6}; //"overwrite"
    std::cout << ref << std::endl;
}

输出是5,然后是6,但定义是否明确?如果是这样,我使用float 作为第二种类型可以吗?

【问题讨论】:

  • 就生命周期而言,您正在取消引用一个悬空指针。不过,现在还不能通过标准来了解它,所以那里有可能是一个极端案例。
  • 您正在通过std::reference_wrapper&lt;int&gt; 访问unsigned int,这是对int 引用的包装。因此,我们可以说您正在通过int &amp; 访问unsigned int。合法吗?我会说 UB。
  • 此外,标准规定 - 应初始化引用以引用有效的对象或函数。因此,您尝试更改底层对象的尝试肯定是有味道的。
  • @marcinj 我从here 得到了定义。话虽如此,这同样适用于指针,因此这里的实现细节似乎毫无意义。通过T * 访问对象U 很少是一个好主意(当然,抛开多态性不谈)。
  • 无论这可能违反什么其他规则(几乎可以肯定它违反了对象生命周期规则之一),它不违反the strict aliasing rule

标签: c++ c++11 reference language-lawyer placement-new


【解决方案1】:

第二个放置 new-expression 重用了由第一个放置 new-expression (@ 987654321@).

由于不满足[basic.life]/8(由于类型差异),引用包装器存储的指针不指向新对象,而是继续指向已过期的int对象.因此,根据[basic.life]/7,通过从此类指针获得的左值访问对象具有未定义的行为。


请注意,严格的别名在这里是无关紧要的;该规则明确允许accessing an object via a glvalue of "a type that is the signed or unsigned type corresponding to the dynamic type of the object"

【讨论】:

    猜你喜欢
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 2016-05-25
    • 2017-11-19
    相关资源
    最近更新 更多