gpt4 book ai didi

c++ - 正在构造格式正确的 char 数组中的对象

转载 作者:太空狗 更新时间:2023-10-29 21:34:53 24 4
gpt4 key购买 nike

这几乎是placement new的标准教科书用法

template<size_t Len, size_t Align>
class aligned_memory
{
public:
aligned_memory() : data((char*)(((std::uintptr_t)mem + Align - 1) & -Align)) {}
char* get() const {return data;}
private:
char mem[Len + Align - 1];
char* data;
};

template<typename T, size_t N>
class Array
{
public:
Array() : sz(0) {}
void push_back(const T& t)
{
new (data.get() + sz++ * sizeof(T)) T(t);
}
void pop_back()
{
((T*)data.get() + --sz)->~T();
}

private:
aligned_memory<N * sizeof(T), alignof(T)> data;
size_t sz;
};

看起来很好,在我们研究严格别名之前,这是否格式良好似乎存在一些冲突

营地病态

阵营结构良好

他们都同意 char* 可能总是引用另一个对象,但有些人指出反过来这样做是不正确的。

很明显,我们的 char[] 转换为 char*,然后转换为 T*,用于调用其析构函数。

那么,上面的程序是否违反了严格的别名规则?具体来说,它在标准中的哪个位置表示它是格式正确的还是格式错误的?

编辑:作为背景信息,这是为 C++0x 编写的,在 alignasstd::launder 出现之前。不是特别要求 C++0x 解决方案,但它是首选。

alignof 是作弊,但这里只是为了举例。

最佳答案

从无数有用的评论中收集到的提示,这是我对正在发生的事情的解释。

TLDR 其格式良好 ‡查看编辑


按照我觉得从 [basic.life] 开始更合乎逻辑的顺序引用

The properties ascribed to objects and references throughout this International Standard apply for a given object or reference only during its lifetime.


An object is said to have non-vacuous initialization if it is of a class or aggregate type and it or one of its subobjects is initialized by a constructor other than a trivial default constructor. [...] The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and

  • if the object has non-vacuous initialization, its initialization is complete.


The lifetime of an object o of type T ends when:

  • if T is a class type with a non-trivial destructor , the destructor call starts, or

  • the storage which the object occupies is released, or is reused by an object that is not nested within o

来自 [basic.lval]

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined

  • the dynamic type of the object,

  • a cv-qualified version of the dynamic type of the object,

  • a type similar to the dynamic type of the object,

  • a type that is the signed or unsigned type corresponding to the dynamic type of the object,

  • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,

  • an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),

  • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,

  • a char, unsigned char, or std​::​byte type.

我们推断

  1. char 的生命周期在 char[] 中当另一个对象重用该空间时结束。

  2. 类型对象的生命周期 T何时开始 push_back被称为。

  3. 自地址((T*)data.get() + --sz)始终是类型为 T 的对象其生命周期已经开始但尚未结束,调用~T()是有效的与它。

  4. 在此过程中,char[]char*aligned_memory别名 T 类型的对象但这样做是合法的。此外,没有从它们获得 glvalue,因此它们可能是任何类型的指针。

在评论中回答我自己的问题,使用任何内存作为存储是否也是良构的

U u;
u->~U();
new (&u) T;
((T*)&u)->~T();
new (&u) U;

按照以上4点,答案是 yes ‡see edit,只要对齐U即可不弱于T .

‡ 编辑:我忽略了 [basic.life] 的另一段

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • the storage for the new object exactly overlays the storage location which the original object occupied, and

  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and

  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

  • the original object was a most derived object of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

这意味着即使使用对象是合式的,但获取对象的方式却不是。具体来说,发布 C++17,std::launder必须调用

(std::launder((T*)data.get()) + --sz)->~T();

在 C++17 之前,解决方法是使用从 new 位置获取的指针

T* p = new (data.get() + sz++ * sizeof(T)) T(t);  // store p somewhere

† 引自 n4659,据我所知,同样适用于 n1905

关于c++ - 正在构造格式正确的 char 数组中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45041045/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com