根据使用的构造函数声明成员

时间:2019-05-13 19:36:47

标签: c++

struct foo
{
    foo(int something) : m_something{ something } {}
    foo() {   }

    private:

        int m_something{};
};

struct bar
{
    bar(foo&  f)
        :
        m_foo{ f }
    {   }

    bar(int something)
        :
        m_default{ something } ,
        m_foo{ m_default }
    {

    }
private:
    foo m_default;
    foo& m_foo;
};

bar类可以通过引用foo来构造,也可以初始化foo本身。如果要通过引用foo构造bar,我想摆脱m_default的不必要的初始化开销。我知道可以通过使用指针来解决,但我想留在堆栈中。

有可能吗?

Ted Lyngmo的回答完美无误。我正在共享完整代码:

#include <iostream>

struct foo;
struct foo_own;

// only holds a reference
struct foo_ref {
    foo_ref(foo& fr) : m_foo(fr) {
        std::cout << "foo_ref constructor is called\n";
    }
    virtual ~foo_ref() = default;

    operator bool() { return false; }
    operator foo&() { return m_foo; }
    foo& operator*() { return m_foo; }

private:
    foo& m_foo;
};

struct foo
{
    foo(int something) : m_something{ something } {}
    foo() {   }

    private:

        int m_something{};
};

// owning a foo
struct foo_own : public foo_ref {
    foo_own(int something) : foo_ref(m_default), m_default(something) {
        std::cout << "foo_own constructor is called\n";
    }

private:
    foo m_default;
};

struct bar
{
    bar(const foo_ref&  f)
        :
        m_foo{ f }
    {   }

    bar(const foo_own& f)
        :
        m_foo{ f }
    {   }

private:
    const foo_ref& m_foo;
};


int main(int, char**) {
    foo foo_l;

    bar b{foo_l};
    bar b2{15};

    return 0;
}

输出为

  

调用foo_ref构造函数
调用foo_ref构造函数
foo_own   构造函数称为

2 个答案:

答案 0 :(得分:2)

您可以将其分为两种foo包装器:

// only holds a reference
struct foo_ref {
    foo_ref(foo& fr) : m_foo(fr) {}
    virtual ~foo_ref() = default;

    operator foo&() { return m_foo; }
    foo& operator*() { return m_foo; }

private:
    foo& m_foo;
};

// owning a foo
struct foo_own : public foo_ref {
    foo_own(int something) : foo_ref(m_default), m_default(something) {}

private:
    foo m_default;
};

为避免将来进行切片,并有一种创建看起来非常相似的foo_reffoo_own的方法,您可以添加几个帮助函数:

auto make_foo_wrapper_ptr(foo& f) {
    return std::make_unique<foo_ref>(f);
}

auto make_foo_wrapper_ptr(int v) {
    return std::make_unique<foo_own>(v);
}

答案 1 :(得分:1)

您可以使用std::variant,它可以为空(表示保留std::monostate)或保留foo。然后应该使m_foo引用第一个构造函数中传递的foo&,或者引用第二个构造函数中的变体所持有的foo

在两种情况下,bar的其余代码应仅使用m_foo,而不管实例是如何构造的,因为这两种方式均引用有效的foo对象。 / p>

这需要C ++ 17支持。

#include <variant>

struct bar
{
    // We do not initialize m_foo_var here so that it's going to be
    // default constructed as empty.
    bar(foo& f)
        : m_foo(f)
    {}

    bar(int something)
        : m_foo_var(something)
        , m_foo(std::get<foo>(m_foo_var))
    {}

private:
    std::variant<std::monostate, foo> m_foo_var;
    foo& m_foo;
};

请注意,这消除了初始化开销,但没有存储器开销。 m_foo_var仍将占据sizeof(foo)个字节。