放置 - 新 STL 容器并在之后安全地销毁它
Placement-new an STL container and destroying it safely afterwards
此代码实现了一个不受限制的联合,它按名称和索引提供对其三个成员中的任何一个的访问。
由于std::string
是非平凡构造和销毁的,因此我需要为union
提供特殊的构造函数和析构函数。
#include <iostream>
#include <string>
using namespace std ;
union MyUnion{
string parts[3] ;
struct{ string part1, part2, part3 ; } ;
MyUnion(){
new(parts+0) string ; //constructs the 3 strings in-place
new(parts+1) string ;
new(parts+2) string ;
}
~MyUnion(){
parts[0].~string() ; //calls string's destructor
parts[1].~string() ;
parts[2].~string() ;
}
} ;
int main(){
MyUnion u ;
u.part1 = "one" ; //access by name
u.part2 = "two" ;
u.part3 = "three" ;
cout << u.parts[0] << endl ; //access by index
cout << u.parts[1] << endl ;
cout << u.parts[2] << endl ;
}
这个例子编译和工作正常(看起来),但我的问题是:
- 这样做安全吗?
- 我可以确定不会有内存泄漏吗?
- 如果
string
的构造函数抛出异常怎么办?是否需要抓住这一点,以免试图破坏从未建造过的物体?
注意
代码在 VC2015中编译,VC2015 确实支持未命名的结构。请忽略这个细节。
这样做
安全吗?
不。首先,通用的初始序列规则只允许读取成员,不允许写入:
在结构类型为
T1
的活动成员(9.3)的标准布局联合中,允许读取结构类型为T2
的另一个联合成员的非静态数据成员m
m
前提是它是T1
和T2
的公共初始序列的一部分;行为就像T1
的相应成员被提名一样。
其次,常见的初始序列是标准布局类型的特征:
两种标准布局结构(条款 9)类型的常见初始序列是 [...]
并且std::string
不需要是标准布局。
这样做
安全吗?
这取决于你愿意称之为安全的东西。该准则当然通过对标准的任何合理解释来调用未定义的行为。
除非涉及公共子序列(9.3 联合),否则您无法读取联合的非活动成员,但这些联合成员没有公共初始序列,因为该概念仅针对两个标准布局结构(9.2 类成员/20)定义,并且联合的一个成员根本不是结构。它是一个数组,因此它不能与任何东西有一个共同的初始序列。
这也适用于使用基元类型的类似代码,例如int x[3];
和struct {int x0, x1, x2};
。甚至不能保证x2
和x[2]
具有相同的地址。
相关文章:
- 从不同线程使用int64的不同字节安全吗
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 在类定义之后定义一个私有方法
- 如何将元素添加到数组的线程安全函数?
- 在循环C++中指定字符串之后,不会打印该字符串
- C++中的线程安全删除
- C++宏忽略之后的内容
- 通过网络、跨平台传递std::变体是否安全
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 在C++"new"运算符之后使用"realloc"是否安全?
- 为什么编译器在我定义_CRT_SECURE_NO_WARNINGS之后仍然警告我不安全的strtok
- 如果我对async_read进行两次调用,那么只有在处理完第一次调用之后,才会处理第二次调用,这是否安全
- 在 std::move 之后重复使用 std 容器是否安全
- 在dlsym之后调用dlclose安全吗
- 在另一个线程写入变量并加入该线程之后,从主线程访问变量是否安全