【发布时间】:2017-05-31 10:01:51
【问题描述】:
在 C++ ISO 标准 N4618 中(但它几乎也适用于 C++11 版本)可以阅读:
在 §1.8 C++ 对象模型:
如果在与“N unsigned char 数组”类型的另一个对象
e关联的存储中创建完整对象(5.3.4),则该数组提供存储 对于创建的对象... [注意:如果数组的该部分先前为另一个对象提供了存储,则该对象的生命周期 结束,因为它的存储被重复使用]
=> OK,unsigned char数组可以为其他对象提供存储空间,如果一个新对象占用了之前被其他对象占用的存储空间,那么新的对象会复用之前的存储空间。
在 §3.8.8 对象生命周期
如果在对象的生命周期结束之后,在对象占用的存储空间被重用或释放之前,在存储位置创建一个新对象原来占用的对象,...
=> 我可以在另一个对象的存储位置构造一个对象,但是这个操作不是“存储重用”(否则为什么要写 ...在对象占用的存储被重用之前...)
作为 §3.8.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;
}
C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C
因此,在本例中,new(this) C(other) 不会是存储重用,因为 c1 具有自动存储持续时间。
在这个例子中恰恰相反:
alignas(C) unsigned char a[sizeof(C)];
auto pc1 = new (&a) C{};
C c2;
*pc1 = c2;
在赋值*pc1=c2 期间评估的表达式new (this) C(other) 是存储重用,因为pc1 指向的对象具有由无符号字符数组提供的存储。
以下断言(以及之前的断言)是否正确:
- 如果初始对象是在无符号字符数组提供的存储上构造的,则§3.8.8 不适用;
- “存储重用”一词仅适用于 unsigned char 数组提供的存储。
编辑:好的,请不要关注“存储重用”术语,而是关注“如果初始对象是在 unsigned char 数组提供的存储上构建的,则第 3.8.8 节不适用”的问题?
因为如果不是这样,那么我所知道的所有 std::vector 实现都不正确。事实上,他们将分配的存储空间保存在 value_type 类型的指针中,例如称为 __begin_。
假设你在这个向量上做了一个 push_back。该对象将在分配存储开始时创建:
new (__begin_) value_type(data);
然后你说清楚,这会调用分配器的销毁,而分配器会调用对象的析构函数:
__begin_->~value_type();
那么如果你做一个新的 push_back,vector 就不会分配新的存储空间了:
new (__begin_) value_type(data);
因此,根据 de §3.8.8,如果 value_type 具有 ref 数据成员或 const 数据成员,那么导致 *__begin_ 的 front 调用将不会指向新的推送对象。
所以我认为存储重用在 $3.8.8 中具有特殊含义,否则,std 库实现者错了吗?我检查了 libstdc++ 和 libc++(GCC 和 Clang)。
在这个例子中会发生什么:
#include <vector>
struct A{
const int i;
};
int main() {
std::vector<A> v{};
A a{};
v.push_back(A{});
v.clear();
v.push_back(A{2});
return 0;
}
【问题讨论】:
-
"这个操作不是"存储重用"" 为什么不呢?我认为您正在尝试阅读不存在的内容。 “重用”不是一个技术术语;它只是简单的英语。如果您在某个存储中创建一个对象,那么您就是在重复使用该存储。
-
这实际上是我在阅读 $3.8.8 之前所相信的,一个对象是在“在存储被重用之前”在另一个对象的存储上构建的??否则如何在第一个对象的存储被重用之前在另一个对象的内存位置构造一个对象??
-
(but it almost also applies to the C++11 version)据我所知,您引用的 §1.8 部分是 C++1z 中的新内容。 -
这就是“几乎”的原因
-
"所以在这个例子中 new(this) C(other) 不会是存储重用,因为 c1 具有自动存储持续时间。" 你是什么意思?
标签: c++ c++11 language-lawyer c++17