List of constructor initializers compared to expensive operations

Consider a hypothetical scenario in which two classes can be built by default or built from each other, but in any case considered expensive (a deliberately contrived example follows):

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...
};

(Of course, this could be reduced to one class, but the justice of the issue has not been touched. Say, for the sake of coherence, there is no symmetry between one and the other.)

Now there is a structure that contains instances of both and needs this cross-initialization. However, we may need both directions, so the initializer lists cannot cut it (they are not executed in the specified order, but in the order in which the members are defined, and the order cannot be fixed here):

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

Of course I could try:

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

, PublicKey X , , . PublicKey::PublicKey(). , , X, - , , , X::X(float). ?

+4
2

, , .

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);
  }
};
+7

, :

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()) {}
};

, .

+3

Source: https://habr.com/ru/post/1658241/


All Articles