相关疑难解决方法(0)

什么是严格别名规则?

当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?

c strict-aliasing undefined-behavior type-punning

778
推荐指数
10
解决办法
19万
查看次数

std :: launder的目的是什么?

P0137引入了函数模板, std::launder并在有关联合,生命周期和指针的部分中对标准进行了许多更改.

这篇论文解决了什么问题?我必须注意哪些语言的变化?我们在做什么launder

c++ memory c++-faq c++17 stdlaunder

223
推荐指数
3
解决办法
2万
查看次数

reinterpret_cast,char*和未定义的行为

什么情况下,reinterpret_cast荷兰国际集团一char*(或char[N])是不确定的行为,当它定义的行为?我应该用什么经验来回答这个问题?


正如我们从这个问题中学到的,以下是未定义的行为:

alignas(int) char data[sizeof(int)];
int *myInt = new (data) int;           // OK
*myInt = 34;                           // OK
int i = *reinterpret_cast<int*>(data); // <== UB! have to use std::launder
Run Code Online (Sandbox Code Playgroud)

但是在什么时候我们可以reinterpret_cast在一个char数组上做一个并且它不是未定义的行为?以下是一些简单的例子:

  1. new,只是reinterpret_cast:

    alignas(int) char data[sizeof(int)];
    *reinterpret_cast<int*>(data) = 42;    // is the first cast write UB?
    int i = *reinterpret_cast<int*>(data); // how about a read?
    *reinterpret_cast<int*>(data) = 4;     // how about the second write?
    int j …
    Run Code Online (Sandbox Code Playgroud)

c++ undefined-behavior language-lawyer reinterpret-cast c++17

13
推荐指数
1
解决办法
1332
查看次数

在 std::launder 之前,所有 std::vector 的实现都是不可移植的吗?

当在实例emplace_back()上调用时std::vector,会在先前分配的存储中创建一个对象。这可以通过 Placement-new 轻松实现,它非常便携。但现在,我们需要访问嵌入的元素而不调用未定义的行为。

这篇文章中 我了解到有两种方法可以做到这一点

  1. 使用placement-new返回的指针: auto *elemPtr = new (bufferPtr) MyType();

  2. 或者,从 C++17 开始,std::launder所转换的指针bufferPtr
    auto *elemPtr2 = std::launder(reinterpret_cast<MyType*>(bufferPtr));

第二种方法可以很容易地推广到这样的情况,即我们有很多对象放置在相邻的内存位置,如std::vector. 但在 C++17 之前人们做了什么?一种解决方案是将placement-new 返回的指针存储在单独的动态数组中。虽然这当然是合法的,但我认为它并没有真正实现 std::vector [此外,单独存储我们已经知道的所有地址是一个疯狂的想法]。另一个解决方案是存储lastEmplacedElemPtrinside std::vector,并从中删除适当的整数 - 但由于我们实际上没有MyType对象数组,这可能也是未定义的。事实上,此 cppreference 页面中的一个示例声称,如果我们有两个相同类型的指针比较相等,并且其中一个可以安全地取消引用,则取消引用另一个可能仍然是未定义的。

那么,在 C++17 之前有没有办法以可移植的方式实现 std::vector 呢?或者也许 std::launder 确实是 C++ 的一个关键部分,当涉及到新的放置时,自 C++98 以来就缺失了?

我知道这个问题表面上与SO上的许多其他问题相似,但据我所知,他们都没有解释如何合法地迭代由placement-new构造的对象。事实上,这一切都有点令人困惑。例如,示例形式的cppreference 文档中的 std::aligned_storage注释 似乎表明 C++11 和 C++17 之间存在一些变化,并且简单的别名违规reinterpret_cast在 C++17 之前是合法的 [无需std::launder]。类似地,在文档 的示例中,std::malloc 他们只是对返回的指针进行指针算术 …

c++ placement-new language-lawyer c++11

10
推荐指数
1
解决办法
486
查看次数

reinterpret_cast vs严格别名

我正在阅读有关严格别名的内容,但它仍然有点模糊,我无法确定定义/未定义行为的界限.我发现最详细的帖子集中在C.所以如果你能告诉我这是否允许以及自C++ 98/11以来发生了什么变化,那将是很好的...

#include <iostream>
#include <cstring>

template <typename T> T transform(T t);

struct my_buffer {
    char data[128];
    unsigned pos;
    my_buffer() : pos(0) {}
    void rewind() { pos = 0; }    
    template <typename T> void push_via_pointer_cast(const T& t) {
        *reinterpret_cast<T*>(&data[pos]) = transform(t);
        pos += sizeof(T);
    }
    template <typename T> void pop_via_pointer_cast(T& t) {
        t = transform( *reinterpret_cast<T*>(&data[pos]) );
        pos += sizeof(T);
    }            
};    
// actually do some real transformation here (and actually also needs an inverse)
// ie this …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing language-lawyer reinterpret-cast

8
推荐指数
2
解决办法
974
查看次数

这是严格的别名违规吗?任何类型指针都可以作为字符指针的别名吗?

我仍在努力理解严格别名允许和不允许的内容。这个具体的例子是否违反了严格的别名规则?如果不是,为什么?是因为我将新的不同类型放入 char* 缓冲区吗?

template <typename T>
struct Foo
{
    struct ControlBlock { unsigned long long numReferences; };
    Foo()
    {
        char* buffer = new char[sizeof(T) + sizeof(ControlBlock)];
        // Construct control block
        new (buffer) ControlBlock{};
        // Construct the T after the control block
        this->ptr = buffer + sizeof(ControlBlock);
        new (this->ptr) T{};
    }
    char* ptr;

    T* get() { 
        // Here I cast the char* to T*.
        // Is this OK because T* can alias char* or because
        // I placement newed a T …
Run Code Online (Sandbox Code Playgroud)

c++ strict

7
推荐指数
2
解决办法
216
查看次数

在没有 std::launder 的情况下将 std::aligned_storage* 重新解释为 T* 是否违反严格别名规则?

以下示例来自cppreference.com 的std::aligned_storage 页面

#include <iostream>
#include <type_traits>
#include <string>

template<class T, std::size_t N>
class static_vector
{
    // properly aligned uninitialized storage for N T's
    typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
    std::size_t m_size = 0;

public:
    // Create an object in aligned storage
    template<typename ...Args> void emplace_back(Args&&... args) 
    {
        if( m_size >= N ) // possible error handling
            throw std::bad_alloc{};
        new(data+m_size) T(std::forward<Args>(args)...);
        ++m_size;
    }

    // Access an object in aligned storage
    const T& operator[](std::size_t pos) const 
    {
        return *reinterpret_cast<const T*>(data+pos);
    } …
Run Code Online (Sandbox Code Playgroud)

c++ strict-aliasing language-lawyer reinterpret-cast

6
推荐指数
1
解决办法
1535
查看次数

严格别名规则

我正在读关于reinterpret_cast及其别名规则的说明(http://en.cppreference.com/w/cpp/language/reinterpret_cast).

我写了那段代码:

struct A
{
  int t;
};

char *buf = new char[sizeof(A)];

A *ptr = reinterpret_cast<A*>(buf);
ptr->t = 1;

A *ptr2 = reinterpret_cast<A*>(buf);
cout << ptr2->t;
Run Code Online (Sandbox Code Playgroud)

我认为这些规则不适用于此:

  • T2是对象的(可能是cv限定的)动态类型
  • T2和T1都是(可能是多级,可能在每个级别的cv限定)指向相同类型T3的指针(因为C++ 11)
  • T2是聚合类型或联合类型,它将上述类型之一保存为元素或非静态成员(包括递归地,包含的联合的子聚合和非静态数据成员的元素):这使得它可以安全地进行转换从结构的第一个成员,从union的一个元素到包含它的struct/union.
  • T2是对象的动态类型的(可能是cv限定的)有符号或无符号变体
  • T2是对象的动态类型的(可能是cv限定的)基类
  • T2是char或unsigned char

在我看来,这段代码是不正确的.我对吗?代码是否正确?

另一方面,连接功能(man 2 connect)和struct sockaddr怎么样?

   int connect(int sockfd, const struct sockaddr *addr,
               socklen_t addrlen);
Run Code Online (Sandbox Code Playgroud)

例如.我们有struct sockaddr_in,我们必须将它转换为struct sockaddr.以上规则也不适用,这个演员是不正确的?

c++ strict-aliasing

5
推荐指数
1
解决办法
591
查看次数