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 构造函数称为
答案 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_ref
和foo_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)
个字节。