Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类数组容器实现与严格别名_C++_Arrays_Containers_Strict Aliasing_Placement New - Fatal编程技术网

C++ 类数组容器实现与严格别名

C++ 类数组容器实现与严格别名,c++,arrays,containers,strict-aliasing,placement-new,C++,Arrays,Containers,Strict Aliasing,Placement New,我正试图实现一个类似数组的容器,它有一些特殊的要求和std::vector接口的子集。以下是代码摘录: template<typename Type> class MyArray { public: explicit MyArray(const uint32_t size) : storage(new char[size * sizeof(Type)]), maxElements(size) {} MyArray(const MyArray&) = delet

我正试图实现一个类似数组的容器,它有一些特殊的要求和std::vector接口的子集。以下是代码摘录:

template<typename Type>
class MyArray
{
public:
    explicit MyArray(const uint32_t size) : storage(new char[size * sizeof(Type)]), maxElements(size) {}
    MyArray(const MyArray&) = delete;
    MyArray& operator=(const MyArray&) = delete;
    MyArray(MyArray&& op) { /* some code */ }
    MyArray& operator=(MyArray&& op) { /* some code */ }
    ~MyArray() { if (storage != nullptr) delete[] storage; /* No explicit destructors. Let it go. */  }

    Type* data() { return reinterpret_cast<Type*>(storage); }
    const Type* data() const { return reinterpret_cast<const Type*>(storage); }

    template<typename... Args>
    void emplace_back(Args&&... args)
    {
        assert(current < maxElements);
        new (storage + current * sizeof(Type)) Type(std::forward<Args>(args)...);
        ++current;
    }

private:
    char* storage = nullptr;
    uint32_t maxElements = 0;
    uint32_t current = 0;
};
在没有发现我的程序被破坏的风险的情况下,什么是正确的实现方法?标准容器是如何实现的?在所有的编译器中,是否都存在使用非文档化编译器内部函数的欺骗行为

有时我看到代码通过void*执行两次静态转换,而不是一次重新解释转换:

Type* ptr = static_cast<Type*>(static_cast<void*>(storage + idx * sizeof(ptr)));
它如何比重新解释演员阵容更好?对我来说,它不能解决任何问题,但看起来过于复杂了

但取消引用数据返回的指针似乎违反了严格的别名规则

我不同意

char*存储和数据返回的指针都指向相同的内存区域

这无关紧要。指向同一对象的多个指针不会违反别名规则

此外,下标运算符将。。。取消对不兼容类型(UB)的指针的引用

但是对象不是不兼容的类型。在emplace_back中,使用placement new将类型的对象构造到内存中。假设没有代码路径可以避免这种新的放置,因此假设subscript操作符返回指向这些对象之一的指针,那么取消对*类型指针的引用是定义良好的,因为它指向兼容的类型对象

这就是与指针别名相关的内容:内存中对象的类型,以及被取消引用的指针的类型。从中转换解引用指针的任何中间指针与别名无关

请注意,析构函数不会调用在存储中构造的对象的析构函数,因此,如果类型不是简单的可析构函数,则行为是未定义的

有时我看到代码在void*中有两个静态转换,而不是一个reinterpret转换:它如何比reinterpret转换更好


我想不出任何情况下的行为会有所不同。

快速看一眼,似乎您将一个正确类型的新对象放置到了存储中,因此应该允许指针将其别名。如果我错了,请详细说明为什么您认为您违反了别名规则。旁注:在初始值设定项列表构造函数中,是否应该将maxElements初始化为init.size?但是,缺少析构函数调用是可疑的。你希望哪种对象是可破坏的,但不是可构造的?我不知道这是如何违反严格的别名规则的?取消对指针的引用会破坏严格的别名规则,这是什么意思?如果不使用对齐存储,您的代码可能会有点低效,因为有时会发出比所需更多的内存读取。否则我不明白为什么这里会违反严格的别名规则。std::copyinit.begin、init.end、reinterpret\u caststorage是错误的。应改为在循环中调用构造。感谢澄清!此外,我还删除了下标和固定析构函数,以使用sfinae,它仅在类型可轻微析构函数的情况下执行优化的释放。
Type* ptr = static_cast<Type*>(static_cast<void*>(storage + idx * sizeof(ptr)));
Type* ptr = reinterpret_cast<Type*>(storage + idx * sizeof(ptr));
auto ptr = reinterpret_cast<Type*>(storage) + idx;