简体   繁体   English

放置新的STL容器,然后安全销毁

[英]Placement-new an STL container and destroying it safely afterwards

This code implements an unrestricted union which provides access by name and by index to any of its three members. 此代码实现了一个不受限制的联合,该联合通过名称和索引提供对其三个成员中任何一个的访问。

Since std::string is non-trivially constructed and destroyed, I need to provide special constructor and destructor for the union . 由于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 ;
}

This example compiles and works fine (seemingly), but my questions are: 此示例可以编译并正常运行(貌似),但是我的问题是:

  • Is it safe to do this? 这样安全吗?
  • Can I be sure that there will be no memory leaks? 我可以确定不会有内存泄漏吗?
  • What if string 's constructor throws an exception? 如果string的构造函数抛出异常怎么办? Does that need to be caught so as to not try to destroy an object that was never constructed? 是否需要抓住它以便不试图破坏从未构造的对象?

Note 注意

The code compiles in VC2015, which does support unnamed structs. 该代码在VC2015中编译,它确实支持未命名的结构。 Please disregard that detail. 请忽略该细节。

Is it safe to do this? 这样安全吗?

No. First, the common initial sequence rule only allows reading of members, not writing: 不会。首先,通用的初始序列规则仅允许读取成员,而不能写入:

In a standard-layout union with an active member (9.3) of struct type T1 , it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2 ; 在具有结构类型T1的活动成员(9.3)的标准布局联合中,允许读取结构类型T2的另一个联合成员的非静态数据成员m ,条件是mT1的公共初始序列的一部分,并且T2 ; the behavior is as if the corresponding member of T1 were nominated. 行为就像提名了T1的相应成员一样。

Secondly, common initial sequence is a trait of standard layout types: 其次,常见的初始序列是标准布局类型的特征:

The common initial sequence of two standard-layout struct (Clause 9) types is [...] 两种标准布局结构(第9条)的常见初始序列为[...]

and std::string is not required to be standard-layout. 并且std::string不需要是标准布局。

Is it safe to do this? 这样安全吗?

It depends on what you are willing to call safe. 这取决于您愿意称之为安全的东西。 The code certainly invokes undefined behaviour by any reasonable interpretation of the standard. 该代码肯定会通过对该标准的任何合理解释来调用未定义的行为。

You cannot read an inactive member of a union, except when there's a common subsequence involved (9.3 Unions), but these union members have no common initial sequence because the notion is only defined for two standard-layout structs (9.2 Class Members/20) and one member of the union is not a struct at all. 您不能读取联盟的非活动成员,除非涉及一个公共子序列(9.3个联盟),但是这些联盟成员没有共同的初始序列,因为该概念仅针对两个标准布局结构定义(9.2类成员/ 20)工会的一个成员根本不是一个结构。 It's an array so it cannot have a common initial sequence with anything. 它是一个数组,因此不能有任何共同的初始序列。

This also applies to analogous code that uses primitive types, eg int x[3]; 这也适用于使用原始类型的类似代码,例如int x[3]; and struct {int x0, x1, x2}; struct {int x0, x1, x2}; . There's not even a guarantee that x2 and x[2] have the same address. 甚至不能保证x2x[2]具有相同的地址。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM