簡體   English   中英

包含與非平凡成員的聯合的類的構造函數和復制構造函數

[英]Constructor and copy-constructor for class containing union with non-trivial members

我正在嘗試實現一個自定義變體類型,它使用union來存儲各種不同類型的數據。 在字段type_id我計划存儲union中存儲的數據的類型。 工會包含非平凡的成員。 這是我目前的實施:

struct MyVariant {
  enum { t_invalid, t_string, t_int, t_double, t_ptr, t_dictionary } type_id;
  union {
    int                             as_int;
    double                          as_double;
    std::string                     as_string;
    std::unique_ptr<int>            as_ptr;
    std::map<int, double>           as_dictionary;
  };
};

我嘗試創建一個MyVariant實例,如下所示:

MyVariant v;

我收到錯誤消息: 調用隱式刪除的MyVariant默認構造函數 所以,我嘗試手動實現構造函數,如下所示:

MyVariant() : type_id{t_int}, as_int{0} {}

這給了我一個類似的錯誤消息: 嘗試使用已刪除的功能 接下來,我嘗試實現以下構造函數:

MyVariant(int value) : type_id{t_int}, as_int{value} {}

並構造我的實例如下:

MyVariant v{123};

=>相同的錯誤消息: 嘗試使用已刪除的功能

我也開始實現一個拷貝構造函數,它看起來如下。 但是,當然這對編譯器錯誤沒有幫助。

MyVariant::MyVariant(const MyVariant& other)
{
    type_id = other.type_id;
    switch (type_id) {
        case t_invalid:
            break;
        case t_string:
            new (&as_string) std::string();
            as_string = other.as_string;
            break;
        case t_int:
            as_int = other.as_int;
            break;
        case t_double:
            as_double = other.as_double;
            break;
        case t_ptr:
            new (&as_ptr) std::unique_ptr<int>(nullptr);
            as_ptr = std::make_unique<int>(*other.as_ptr);
            break;
        case t_dictionary:
            new (&as_dictionary) std::map<int, double>();
            // TODO: copy values from other
            break;
    }
}

我使用Xcode和Apple LLVM 6.1作為編譯器。

主要問題是:為什么我會得到我正在獲得的編譯器錯誤以及如何修改我的代碼以使其編譯?

另外一個問題是:我是否正確地使用構造函數和復制構造函數的實現?

您的union具有stringunique_ptrmap類型的數據成員,所有這些都具有非平凡的默認/復制/移動構造函數,復制/移動賦值運算符和析構函數。 因此,所有這些都被隱含地刪除了你的聯盟。

§9.5/ 2 [class.union]

... [ 注意 :如果union的任何非靜態數據成員具有非平凡的默認構造函數(12.1),復制構造函數(12.8),移動構造函數(12.8),復制賦值運算符(12.8),移動賦值運算符( 12.8)或析構函數(12.4),聯合的相應成員函數必須由用戶提供,否則將為聯合隱式刪除(8.4.3)。 - 尾注 ]

所以你必須手動為你的工會實現這些。 至少,為了能夠創建MyVariant的實例,該類需要是可構造和可破壞的。 所以你需要

MyVariant() : type_id{t_int}, as_int{0} {}
~MyVariant()
{
  switch(type_id)
  {
      case t_int:
      case t_double:
        // trivially destructible, no need to do anything
        break;
      case t_string:
        as_string.~basic_string();
        break;
      case t_ptr:
        as_ptr.~unique_ptr();
        break;
      case t_dictionary:
        as_dictionary.~map();
        break;
      case t_invalid:
        // do nothing
        break;
      default:
        throw std::runtime_error("unknown type");
  }
}

你的拷貝構造函數實現看起來是有效的,但是我做的不同的是首先默認構造成員,然后從源對象復制,只需復制構建新的調用本身。

MyVariant(const MyVariant& other)
{
  type_id = other.type_id;
  switch (type_id) {
      case t_invalid:
          break;
      case t_string:
          new (&as_string) auto(other.as_string);
          break;
      case t_int:
          as_int = other.as_int;
          break;
      case t_double:
          as_double = other.as_double;
          break;
      case t_ptr:
          new (&as_ptr) auto(std::make_unique<int>(*other.as_ptr));
          break;
      case t_dictionary:
          new (&as_dictionary) auto(other.as_dictionary);
          break;
  }

現場演示

請注意,如果unique_ptr成員處於活動狀態,並且通過基類指針存儲指向某個派生類實例的指針,則復制構造函數實現將僅復制基類部分。

最后,除非你把它作為一個學習練習,否則我強烈建議你使用Boost.Variant而不是自己動手。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM