簡體   English   中英

構造函數初始化列表與昂貴的操作

[英]Constructor initializer list vs. expensive operations

考慮一個假設的場景,其中兩個類可以默認構造或相互構造,但任何一種方式都被認為是昂貴的(有意設計的例子如下):

struct PrivateKey;

struct PublicKey {
  PublicKey(); // generate a random public key (1 minute)
  PublicKey(const PrivateKey& b); // find a public key corresponding to a private key (1 year)
  ...members...
};

struct PrivateKey {
  PrivateKey(); // generate a random private key (1 minute)
  PrivateKey(const PublicKey& a); // find a private key corresponding to a public key (1 year)
  ...members...
};

(這當然可以濃縮為一個類,但問題的有效性不受影響。讓我們說,為了連貫,在一個和另一個之間沒有對稱性。)

現在有一個結構可以保存兩者的實例並需要這種交叉初始化。 但是,我們可能需要兩個方向,因此初始化程序列表無法真正刪除它們(它們不按列出的順序運行,而是按成員定義的順序運行,並且此處無法修復訂單):

struct X {
  PublicKey a;
  PrivateKey b;
  X(int): a(), b(a) { }
  X(float): b(), a(b) { } // UB: a(b) happens before b is initialized
};

我當然可以嘗試:

struct X {
  PublicKey a;
  PrivateKey b;
  X(int): a(), b(a) { }
  X(float): a(), b() { a = PublicKey(b); }
};

但這有多個問題,其中在X的第二個構造函數中運行昂貴PublicKey 默認構造只是為了立即拋出結果只是第一個。 PublicKey::PublicKey() 可能有副作用 兩者仍然可以通過創建一個只暴露給朋友X的廉價私有構造函數來緩解,這會使該類處於某種虛擬狀態,但會拋出一些引用或常量成員, 並且該類可能無法移動 - 可分配或可交換 ,禁止任何變化在X::X(float)的身體上。 是否有更好的模式可供遵循?

通過使用指向包含的類的指針,而不是直接嵌入包含的類,並在構造函數體內自己構造包含的對象,可以避免構造順序問題。

struct X {
  std::unique_ptr<PublicKey> a;
  std::unique_ptr<PrivateKey> b;
  X(int) {
    a = std::make_unique<PublicKey>();
    b = std::make_unique<PrivateKey>(*a);
  }
  X(float) {
    b = std::make_unique<PrivateKey>();
    a = std::make_unique<PublicKey>(*b);
  }
};

如果類至少是可移動構造的,那么您應該能夠這樣做:

struct KeyPair
{
  PublicKey a;
  PrivateKey b;
  KeyPair(std::pair<PublicKey, PrivateKey> &&data) :
    a(std::move(data.first)),
    b(std::move(data.second))
  {}
};

std::pair<PublicKey, PrivateKey> computePublicFirst()
{
  PublicKey a;
  PrivateKey b(a);
  return {std::move(a), std::move(b)};
}

std::pair<PublicKey, PrivateKey> computePrivateFirst()
{
  PrivateKey b;
  PublicKey a(b);
  return {std::move(a), std::move(b)};
}

struct X
{
  KeyPair keys;
  X(int) : keys(computePublicFirst()) {}
  X(float) : keys(computePrivateFirst()) {}
};

沒有移動任務發生,只移動施工。

暫無
暫無

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

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