联盟成员有一个非平凡的拷贝构造函数

时间:2011-09-04 12:23:50

标签: c++ string constructor

我有一个看起来像这样的联盟:

union {
  int intValue;
  double doubleValue;
  std::string stringValue;
  void *pointerValue;
} values;

当我编译它时,我收到此错误消息(是的,我做了#include <string>):

./Value.hh:19:19: error: union member 'stringValue' has a non-trivial copy constructor                 
      std::string stringValue;                                                                         
                  ^                                                                                    
/Developer/SDKs/MacOSX10.7.sdk//usr/include/c++/4.2.1/bits/basic_string.h:434:7: note: because         
      type 'std::basic_string<char>' has a user-declared copy constructor                              
      basic_string(const basic_string& __str);                                                         
      ^

我使用此命令编译它:

$ clang++ *.cc -isysroot /Developer/SDKs/MacOSX10.7.sdk/ -shared

如何在联盟中使用std::string

5 个答案:

答案 0 :(得分:24)

你不能。

联合结合了两个功能:存储可能具有选定数量类型的对象的能力,以及在这些类型之间有效(和实现定义)转换的能力。您可以放入一个整数并将其表示视为double。等等。

因为联合必须支持这些功能的两个(并且由于其他一些原因,比如能够构造一个),联盟会阻止你做某些事情。也就是说,您不能在其中放置“实时”对象。任何“生存”足够需要非默认复制构造函数的对象(在许多其他限制中)都不能成为联合的成员。

毕竟,union对象实际上没有它实际存储的数据类型的概念。它不存储一种类型的数据;它同时存储所有。你可以钓到正确的类型。那么怎么能合理地将一个联合价值复制到另一个呢?

union的成员必须是POD(普通旧数据)类型。虽然C ++ 11确实放松了这些规则,但对象仍然必须具有默认(或其他微不足道的)复制构造函数。而std::string的复制构造函数并不重要。

您可能想要的是boost::variant。这是一个可以存储许多可能类型的对象,就像联合一样。然而,与联盟不同,它是类型安全的。因此,它知道联盟中究竟是什么;因此,它能够复制自身,并且行为类似于常规C ++对象。

答案 1 :(得分:5)

你不能将std::string放在一个联盟中。它被C ++语言禁止,因为它不安全。考虑到大多数std::string实现都有一个指向某个动态内存的指针,该内存保存了字符串的值。还要考虑无法知道哪个工会成员当前处于活动状态。

实现无法调用std::string的析构函数,因为它不知道std::string对象是当前活动的成员,但如果它不调用析构函数,那么内存将被泄露。 / p>

答案 2 :(得分:3)

根据C ++标准§9.5.1:

具有非平凡构造函数,非平凡复制构造函数,非平凡析构函数或非平凡复制赋值运算符的类的对象不能是联合的成员。

因此,union的成员不能具有构造函数,析构函数,虚拟成员函数或基类。因此,您不能将std :: string用作union的成员。

替代解决方案:

您可以使用 boost :: variant boost :: any

答案 3 :(得分:2)

不幸的是,您不能在联合中使用非POD(普通旧数据)类型。 一个相当典型和简单的解决方法是将union包装在一个struct中, 并将非POD实例从联合内部移动到结构。

例如:

struct Value {
    union {
        int intValue;
        double doubleValue;
        void *pointerValue;
    };
    std::string stringValue;
};

Value value;

// Demonstration of accessing members:

value.intValue = 0;
value.doubleValue = 0.0;
value.pointerValue = NULL;
value.stringValue = "foo";

然而,您确实为此付出了代价 - Value结构的内存占用量将大于原始联合的内存占用量。

答案 4 :(得分:1)

union不能包含以下类型的成员§9.5/ 1:

  

具有非平凡构造函数(12.1)的类的对象,非平凡的复制构造函数(12.8),非平凡的析构函数(12.4)或非平凡的复制赋值运算符(13.5.3, 12.8)不能是一个联合的成员,也不能是一系列这样的对象。

因此要么将指向std :: string的指针定义为:

union {
  int intValue;
  double doubleValue;
  std::string *stringValue; //pointer
  void *pointerValue;
} values;

或者,使用称为Boost.Variant

的boost union