在C ++中,我们可以将对象分配给非const引用。所以这有效:
Foo &foo = Foo();
但是,C ++不允许将临时指定给非const引用。所以这是不允许的:
Bar::Bar(Foo &foo = Foo()) {}
但这是允许的
Bar::Bar(const Foo &foo = Foo()) {}
我在这里有三个问题:
提前致谢。
答案 0 :(得分:3)
在最后一种情况下
foo
的范围是什么?
foo
是一个构造函数(同样适用于常规函数)参数,因此它的生命周期在the full expression containing the call to the constructor ends时结束。 谢谢aschepler!
默认参数的生命周期是什么,在本例中为foo?
通过将默认参数绑定到Foo const& foo
来延长默认参数的生命周期,因此它的生命周期将与其绑定的引用的生命周期匹配,即直到构造函数体退出。
我在MSVC中尝试了第二个例子并没有抱怨。
如果您将警告级别设置为/W4
,则会执行此操作;在这种情况下,它会警告你使用的是非标准扩展。 AFAIK,语义与前一种情况相同。
我的场景以这种方式要求构造函数的默认参数,我需要修改构造函数中的参数(所以我不能使它成为const)。并且我还需要在构造函数退出后使用foo。
这取决于您是否要将其保存为Bar
的成员。如果是前者,请使用右值引用并移动参数
Bar::Bar(Foo&& foo = Foo()) : f_(std::move(foo)) {} // f_ is a member of type Foo
否则,请忽略默认参数。您还可以创建两个重载以涵盖不同的情况。
答案 1 :(得分:1)
foo
及其临时性在构造函数完成后消失。答案 2 :(得分:0)
在这种情况下(与大多数情况一样),直接绑定到引用的临时绑定的生命周期将扩展到引用的生命周期。因此,只要foo
为临时,临时将是有效的,即在构造函数的持续时间内。当包含构造函数调用的完整表达式结束时,它将结束。
MSVC有一个扩展,允许临时绑定到非const引用。它不是标准的,其他编译器也不支持它。除非您(并且将始终)仅编码MSVC,否则请勿使用此项。
这取决于您实际想要达到的目标 - 您的问题中没有足够的信息来回答这个问题。如果在构造函数退出后仍需要它持久化,则需要提供具有适当生命周期的实际对象。您可以提供每线程静态成员,例如:
class Bar
{
static thread_local Foo ctor_default_foo;
public:
Bar(Foo &foo = ctor_default_foo) {}
};
请注意,这当然意味着一个线程使用默认参数创建的所有对象将共享相同的Foo
对象。如果您需要为每个Bar
对象添加一个新对象,则必须更改您的设计。但是要告诉你如何,我们需要更多地了解实际用例。
答案 3 :(得分:0)
我的场景以这种方式要求构造函数的默认参数 我需要修改构造函数中的参数(所以我不能 使它成为const)。我还需要在构造函数之后使用foo 退出。迎合这种情况的最佳设计是什么?
您可以在optional<Foo>
内设Bar
,如下所示:
struct Bar
{
Bar() : optionalFoo(boost::in_place()), foo(*optionalFoo) {}
Bar(Foo& f) : foo(f) {}
Bar(Bar const&) = delete; // Compiler generated one is incorrect
private:
boost::optional<Foo> optionalFoo;
Foo& foo;
};
但是可选地拥有数据的类变得棘手,特别是在复制/移动时。