【问题标题】:C++ Declare const variable, but postpone its initialisation?C++ 声明 const 变量,但推迟初始化?
【发布时间】:2017-08-15 13:31:10
【问题描述】:

上下文

一个函数(来自一些我无法修改的 API)从 objectRegistry 返回一个对对象的常量引用:

const Foo& f(args)

我需要获取常量 Foo 对象,但我需要基于某些条件的 Foo 的不同实例。

天真,我先声明 f 返回什么,然后调用 f 来初始化变量 foo。

const Foo& foo; // Declare
if( something == true ){
    foo = f(arg1); // Initialise
}else{
    foo = f(arg2); // Initialise
}
// It is guaranteedly initialised in this line

这将不起作用,因为这将首先(我假设)调用带有空参数的构造函数。之后,您有一个无法覆盖的 const 对象。相反,编译器立即抱怨:error: 'foo' declared as reference but not initialized。如果将 foo 声明为 const Foo foo;

,也会出现同样的问题

以下确实有效。

const Foo* fooPtr;
if( something == true ){
    fooPtr = &f(1);
}else{
    fooPtr = &f(2);
}
const Foo& foo = *fooPtr;

问题

  • 这种方法除了丑(imo)还有什么问题吗?
  • 有没有更好的方法来达到同样的目的?

有些相关的话题

【问题讨论】:

  • 我以前见过这个问题。答案:三元条件。
  • const Foo foo = *fooPtr; 将创建一个新对象。可能你想写const Foo & foo = *fooPtr;
  • @Kevin van As 条件运算符呢?
  • const Foo& some_name = make_foo(some_parameter);?

标签: c++ initialization const-reference


【解决方案1】:

你可以使用包装器

const Foo& getFooWrapper(something) {  // assume returning a ref is fine,                                         
    if (something) return f(1);        // because f already returns a const&
    else           return f(2);
}

然后简单

const Foo& foo = getFooWrapper();

【讨论】:

  • 嗯,应该可以的。不过,问题是,你的意思是写const Foo& getFooWrapper...(所以有参考)?否则对象会被复制,不是吗?
  • @KevinvanAs no,该函数不应返回引用,因为该引用在函数范围之外是无效的。你可以争论const,但我会为了记录而留下它,因为我理解你的问题const 是必不可少的(我的意思是否则编写这个包装器就没有意义了)
  • const 确实是必不可少的,因为函数 f 返回一个 const。我不能/不应该 const_cast 离开。 ___ 我不明白为什么“该值在函数范围之外无效”。我知道您不能获取临时地址,但是如果 f 返回一个 const&,那么您可能会认为让 getFooWrapper 返回一个 const& 也是安全的?这将是完全相同的 const&?我看不出问题出在哪里。您介意澄清一下吗?
  • @Kevinvan 是的,我忽略了它,没有看到f 返回引用,所以返回引用应该没问题。关于const,我不确定您是否有误解或者我是否误解了您....您始终可以复制const 对象并使用该副本做任何您喜欢的事情,因此对于返回类型Fooconst Foo 没有区别(尽管它是为了参考)
  • @Kevinan 没错,只是返回值优化 (RVO) 如此普遍,以至于您几乎可以肯定它会发生。不过,您是完全正确的:如果 f 返回一个引用,那么从包装器返回一个 Foo 会引入不必要的副本