这是C++ 20规范([basic.life]/8)中的代码示例:

struct C {
  int i;
  void f();
  const C& operator=( const C& );
};

const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();              // lifetime of *this ends
    new (this) C(other);     // new object of type C created
    f();                     // well-defined
  }
  return *this;
}

int main() {
  C c1;
  C c2;
  c1 = c2;   // well-defined
  c1.f();    // well-defined; c1 refers to a new object of type C
}

以下是合法还是未定义行为:
struct C {
  int& i; // <= the field is now a reference
  void foo(const C& other) {
    if ( this != &other ) {
      this->~C();
      new (this) C(other);
    }
  }
};

int main() {
    int i = 3, j = 5;
    C c1 {.i = i};
    std::cout << c1.i << std::endl;
    C c2 {.i = j};
    c1.foo(c2);
    std::cout << c1.i << std::endl;
}

如果非法std::launder会使其合法吗?应该在哪里添加?

注意: p0532r0 (page 5)在类似情况下使用洗手池。

如果它是合法,那么在没有“指针优化障碍”(即std::launder)的情况下如何工作?我们如何避免编译器缓存c1.i的值?

该问题与有关Implementability of std::optional 的旧ISO线程有关。

这个问题也非常类似地适用于常量字段(即,如果i中的struct C以上为:const int i)。

编辑

@Language Lawyer的似乎指出in an answer below ,规则已在C++ 20中更改,以响应RU007/US042 NB comments

C++ 17规范[ptr.launder](第21.6.4.4节):-强调我的-



规范中的 C++ 17 [ptr.launder]代码示例(第21.6.4.5节):
struct X { const int n; };
X *p = new X{3};
const int a = p->n;
new (p) X{5}; // p does not point to new object (6.8) because X::n is const
const int b = p->n; // undefined behavior
const int c = std::launder(p)->n; // OK

C++ 20 [ptr.launder]规范(第17.6.4.5节):



注意该部分:



C++ 17中出现的错误已在C++ 20中删除,并且相应地更改了示例。

规范中的 C++ 20 [ptr.launder]代码示例(第17.6.4.6节):
struct X { int n; };
const X *p = new const X{3};
const int a = p->n;
new (const_cast<X*>(p)) const X{5}; // p does not point to new object ([basic.life])
                                    // because its type is const
const int b = p->n;                 // undefined behavior
const int c = std::launder(p)->n;   // OK

因此,显然相关代码在C++ 20中是合法的,而在C++ 17中,访问新对象时需要使用std::launder

公开问题:
  • 在C++ 14或更早版本中(当std::launder不存在时),这种代码是什么情况?大概是UB-这就是为什么std::launder被带到游戏中的原因吧?
  • 如果在C++ 20中对于这种情况我们不需要std::launder,那么编译器如何才能理解在没有我们帮助的情况下(即在没有“指针优化障碍”的情况下)正在操纵引用,从而避免了引用值的缓存?


  • 类似的问题herehereherehere得到了矛盾的答案,有些人认为这是有效的语法,但建议重写它。我主要关注语法的有效性以及在不同C++版本中对std::launder的需要(是或否)。

    最佳答案

    要回答当前 Unresolved 问题:

    第一个问题:



    是的,那是UB。 NB问题@Language Lawyer中明确提到了这一点:



    第二个问题:



    如果在两次使用该对象之间调用了非常量成员函数,或者以该对象作为参数调用了任何函数(通过by-ref传递),则编译器已经知道不会以这种方式优化对象(或子对象)的值,因为该值可能会被这些功能更改。对该标准的更改仅增加了一些其他情况,其中这种优化是非法的。

    10-08 02:10