如何根据参数在复制构造函数和默认构造函数之间切换

How to switch between copy-constructor and default constructor depending on argument?

本文关键字:构造函数 默认 之间 复制 何根 参数      更新时间:2023-10-16

我有以下代码:

struct S
{
    S(): a(42) {}
    int a;
};
class P
{
public:
    P(S const *s): m_s(s ? *s : /*init m_s by default ctor - how to achieve it?*/)
private:
    S m_s;
};

我希望m_s由复制构造函数或默认构造函数初始化,具体取决于指针s:

P p1(nullptr); // expect default ctor: p1.m_s.a = 42
S s;
s.a = 84;
P p2(&s); // expect copy ctor: p2.m_s.a = 84

我怎样才能用最优雅的方式来做呢?

您可以只写:

class P {
public:
    P(S const *s): m_s(s ? *s : S()){}
private:
    S m_s;
};

您可能会发现将条件提取到一个单独的辅助函数更优雅:

S createS(S const *s) {
  return s ? *s : S();
}

nullptr参数的情况下,这看起来可能会执行不必要的复制,但实际上编译器会执行RVO并优化复制。

现场演示。

一个仅适用于空指针常量的部分解决方案是添加一个重载:

P(std::nullptr_t) : m_s() {}
P(const S * s) : m_s(AssertNotNull(s)) {}

这里我使用:

template <typename T> T * AssertNotNull(T * p) {
  if (!p) std::abort();
  return p;
}

如果你需要一个动态开关,你可以使用一个辅助功能:

struct P {
  static const S & maybe(const S * s) {
    static S x;
    return s ? *s : x;
  }
  P(const S * s) : m_s(maybe(s)) {}
  S m_s;
}

这实际上并没有在复制和默认构造函数之间切换(因为你不能动态地这样做),但如果指针为null,它会通过从默认构造的实例复制来伪造效果。