【问题标题】:Using std::launder to "validate" non "pointer to object" pointer value since C++17自 C++17 以来,使用 std::launder 来“验证”非“指向对象的指针”指针值
【发布时间】:2018-06-12 12:44:14
【问题描述】:

根据answer,从 C++17 开始,即使指针具有正确的地址和正确的类型取消引用它也可能导致未定义的行为

 alignas(int) unsigned char buffer[2*sizeof(int)];
 auto p1=new(buffer) int{};
 auto p2=new(p1+1) int{};
 *(p1+1)=10; // UB since c++17

原因是p1+1的指针值是a pointer past-the-end of一个对象。可以使用std::launder 将这个示例恢复到定义的行为:

 *std::launder(p1+1)=10; // still UB?  

其次,在下面这种情况下也有用吗?

alignas(int) unsigned char buffer[3*sizeof(int)];
auto pi = new (buffer) int{};
auto pc = reinterpret_cast<unsigned char*>(pi);//not a "pointer to" an element of buffer 
                                               //since buffer[0] and *pc 
                                               //are not pointer interconvertible
//pc+2*sizeof(int) would be UB
auto pc_valid = std::launder(pc) //pc_valid is a pointer to an element of buffer
auto pc_valid2 = pc_valid+2*sizeof(int); //not UB thanks to std::launder
auto pi2 = new (pc_valid2) int{};

【问题讨论】:

    标签: c++ pointers c++17


    【解决方案1】:

    没有。构成int对象p2指向的字节不是reachablep1+1


    “可达”规则基本上意味着launder 不允许您访问您无法通过原始指针合法访问的存储。由于一个不透明的函数可以launder 指针尽可能多地使用它,因此允许这种恶作剧将大大抑制逃逸分析。

    【讨论】:

    • 第二个例子,有意义吗?
    • 同样的答案。数组的剩余2*sizeof(int) 字节无法通过pi 访问。
    • 直到 cxxdraft-htmlgen 也创建指向单个句子的链接。整洁
    • @TC:我当然可以看到有必要将永远不会用于派生外部对象的指针与可能用于派生外部对象的指针区分开来,但是一种没有任何指针类型可以保留能力的语言导出外部对象的地址从根本上比导出的要弱。
    • @TC:此外,通常需要的不是清洗指针并使其无限期可用的能力,而是创建指向可以访问其他对象的对象的指针的能力,但是,它的生命周期会受到类似于 C 的restrict 的限制。本质上,这样一个指针的创建和销毁将充当排序障碍,但使用它们不会。在紧密循环中创建此类指针的代码可能会表现不佳,但能够在循环之外放置障碍可能会产生比其他方法更有效的代码。
    猜你喜欢
    • 2019-01-04
    • 1970-01-01
    • 2019-10-11
    • 2021-02-17
    • 2017-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多