对象生存期和未定义的行为



在3.8对象生存期中,有以下部分

在对象的生存期开始之前,但在存储之后对象将占据的位置已被分配40,或者在对象的生存期已结束,并且在存储之前被占用的对象被重用或释放,任何指向可以使用对象将要或曾经所在的存储位置但仅以有限的方式。对于在建物体或销毁,见12.7。否则,这样的指针指的是已分配的存储(3.7.4.2),并将指针当作类型void*,定义良好。通过这样一个指针的间接性允许,但是所得到的左值可以仅以有限的方式使用,如下所述。程序具有未定义的行为,如果:

指针用于访问非静态数据成员或调用对象的非静态成员函数

有人能提供一个例子来解释上述语句吗?

下面是一个带有注释的示例:

#include <cstdlib>
#include <iostream>
#include <string>
int main() {
void* storage = std::malloc(sizeof(std::string));

// Before the lifetime of the object has started but after the
// storage which the object will occupy has been allocated
// starting the lifetime of the object:
std::string* a_string_ptr = new(storage) std::string;
*a_string_ptr = "Hello world, what is going on?";
std::cout << *a_string_ptr << 'n';
// ending the lifetime of the object
a_string_ptr->~basic_string();

// after the lifetime of the object has ended and before the storage
// which the object occupied is reused or released
std::free(storage);
// after the storage which the object occupied is released
}

一些例子(还有许多其他方法):

struct A {
void f() {};
};
int main() {
A a = ((&a)->f(), A{}); //1
a.~A();
(&a)->f(); //2
A b = (*&b, A{}); //3
b.~A();
(*&b, 0); //4
}

在所有四种标记的情况下,由&形成并取消引用的指针都不是无效,因为这些求值发生在ab对象的存储期间。

但在//1中,对f的调用是在a的初始化完成之前进行的,也就是说,在其生命周期开始之前,在其构造函数开始之前,因此引用的段落适用。

//2中,对f的调用是在调用a的析构函数之后进行的,这意味着它的生存期已经结束,因此引用的段落也适用。

因此CCD_ 10和CCD_。

相反,//3//4是好的。它们在生存期之外形成并取消引用指针,但在您引用的段落之后,不会违反[basic.life]中glvalues的任何规则。特别是,不执行对标量的访问,也不访问非静态成员。


然而,引用的限制可能与后来对在生存期之外使用glvalues的限制是多余的,后者也禁止调用非静态成员函数或访问非静态数据成员。但通过指针实现这一切的唯一方法是首先取消引用指针以获得glvalue。(这就是*->的定义。)

最新更新