【问题标题】:Declare a reference and initialize later?声明一个引用并稍后初始化?
【发布时间】:2013-02-14 19:59:02
【问题描述】:

我引用了某个类 MyObject,但确切的对象取决于条件。我想做这样的事情:

MyObject& ref; 
if([condition]) 
  ref = MyObject([something]);
else 
  ref = MyObject([something else]);

我现在不能这样做,因为编译器不允许我声明但不能初始化引用。我可以做些什么来实现我的目标?

【问题讨论】:

  • 这会是临时的初始化吗?即使没有条件:MyObject& ref = MyObject([something]);,这也行不通,因为您不能将临时对象绑定到非 const 左值引用。
  • @GManNickG :这也适用于 Zaffy 和 suszterpatt 的答案?
  • @qPCR4vir:是的。这个问题在某种程度上仍然存在,只是不直接。
  • 如果您正在寻找实际解决方案,请向下滚动至stackoverflow.com/a/50909452/1021920

标签: c++ reference


【解决方案1】:

你需要初始化它。但是如果你想有条件地初始化它,你可以这样做:

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);

【讨论】:

  • 我不能这样做,因为我实际上是在这些条件下做的。我在这里很困惑。对我来说,这看起来很常见,为什么不允许这样做?我的编码风格是反 C++ 的吗?
  • @user1861088:“我不能这样做,因为我实际上是在这些条件下做的”那么你为什么不在问题中实际展示你想要做的事情呢?
  • 我的意思是我在每个条件中执行多行代码,而不是只调用一个返回值的函数。所以我不能用? :对吗?
  • @user1861088 你不能初始化引用,然后再次测试条件并执行多行代码吗?引用一旦创建就不能更改。引用永远不能为空。这两件事使您无法执行您在问题中发布的内容。
  • 你可以考虑使用 lambda。
【解决方案2】:

AFAIK 这不能通过参考来完成。您必须使用指针:

MyClass *ptr;

if (condition)
    ptr = &object;
else
    ptr = &other_object;

指针的作用类似于引用。只是不要忘记使用-> 进行会员访问。

【讨论】:

  • 如果你想把它变成一个引用,你可以声明一个引用为MyClass &ref = *ptr...
  • 将其声明为指针并不能解决右值作为函数返回的情况
  • 不,它不会与引用类似,因为它将被放置在堆上并且需要手动删除。
  • @JosuGoñi 两者都不是真的。仅当我要分配内存时(通过new)。 ptr 指向堆栈上分配的对象。
  • @JosuGoñi 分配给指针不会导致复制或移动。虽然我承认我的答案不是最好的,但它是在我几乎一无所知的时候写回来的。今天我想说把ptr 变成一个值类型并赋值给值。如果它不能被默认初始化,那么我会说使用std::unique_ptr 并在每个条件中使用std::make_unique<MyClass>(...) 分配。
【解决方案3】:

你不能这样做。引用必须绑定到某个东西,你可能不喜欢它,但它可以防止一整类错误,因为如果你有一个引用,你总是可以假设它绑定到某个东西,不像指针可能为空。

您的示例代码无论如何都不起作用,因为您尝试将非常量引用绑定到一个无效的临时对象。

为什么你仍然需要它作为参考?一种解决方案是确保您的类型具有廉价的默认构造函数并且可以有效地移动,然后就这样做:

MyObject obj; 
if([condition]) 
  obj = MyObject([something]) 
else 
  obj = MyObject([something else]);

否则,您必须将条件代码放在一个或多个函数中:

const MyObject& ref = createObject([condition]);

const MyObject& ref = [condition] ? doSomething() : doSomethingElse();

请注意,这两个版本都使用 const 引用,它可以绑定到临时对象,如果对象必须是非常量,则再次停止尝试使用引用:

MyObject obj = createObject([condition]);

感谢return value optimization,这可能与您尝试做的一样有效

【讨论】:

  • 这应该是首选答案!
【解决方案4】:

我喜欢做的是立即执行的 lambda。

假设我们想要一个 const std::string& 到映射下的变量 - 如果映射不包含给定的键 - 我们想要抛出。

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = [&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  }(); // <- here we immediately call just created lambda.
}

您还可以使用 std::invoke() 使其更具可读性(C++17 起)

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = std::invoke([&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  });
}

【讨论】:

  • 是的。如果只有 ppl 会回答一个问题,而不是更愿意建议这个问题不应该被问到。这可能是实际解决 OP 的最干净的即时方法。 +1。人们应该更频繁地向下滚动.. 大声笑
【解决方案5】:

在 C++ 中,您不能在没有初始化的情况下声明引用。你必须初始化它。

【讨论】:

  • 我明白这一点。那么有什么关于四处走走的建议吗?基本上我需要的参考范围比条件更大。
  • @user1861088 在这种情况下,要么 1. 重新设计代码(首选),2. 使用指针(不首选)。
  • 3.不要使用引用,只需使用对象
  • @user529758 对于在类中声明的引用变量是真的吗? class test{ test(param o ):ref(o){}myobj&amp; ref;}
【解决方案6】:

简短的回答:你不知道。

略长一点的答案:做这样的事情:

MyObject& getObject()
{
    if([condition]) 
        return [something] 
    else 
        return [something else];
}

MyObject& ref = getObject();

当然适用关于参考的一般免责声明。

【讨论】:

  • 是的,我想到了这个,但是.. 很奇怪我必须做这一切来实现一个看似简单的目标:(
  • 为什么getObject() 返回一个引用?它指的是什么?
  • &Jonathan:这属于“通常的免责声明”位。 ;)
  • @user1861088 你看似简单的目标是标准不允许的。它与引用的定义相冲突。你不妨问一下,为什么不能简单地把一块石头扔到空中,让它不掉到地上。这很简单——只要扔石头,它就会固定在原地。
【解决方案7】:
MyClass *ptr;

if (condition)
    ptr = &object;
else
    ptr = &other_object;

MyClass &ref = *ptr;

【讨论】:

  • 在回答时,请考虑为您编写的代码写一个解释,这个答案绝对没有为这个非常老问题增加任何新内容。
  • 这看起来与this answer的代码非常相似。
  • 虽然缺乏任何解释是不好的,但这仍然是唯一真正的答案,它不会引入任何额外的东西或限制你可以用三元运算符编写什么......
  • @ArtjomB。该答案没有在末尾提出MyClass &amp;ref = *ptr;,这是此处避免以后进一步取消引用的关键线,进一步评论于:stackoverflow.com/a/62793754/895245
【解决方案8】:

使用静态假人作为占位符。或 std::optional 与 reference_wrapper。

static X placeHolder_;
std::reference_wrapper<X> ref = placeHolder_;
   


std::optional<std::reference_wrapper<X>> ref ;    

【讨论】:

    【解决方案9】:

    我通常这样做(C++ 11 或更高版本):

    std::shared_ptr<ObjType> pObj;
    if(condition)
        pObj = std::make_shared<ObjType>(args_to_constructor_1);
    else
        pObj = std::make_shared<ObjType>(args_to_constructor_2);
    

    它是干净的并且允许使用带有(可能不同的)构造的对象定义,这是你不能直接用指针做的事情,因为编译器会抱怨使用临时对象。

    【讨论】:

      【解决方案10】:

      如果([条件]) MyObject& ref = MyObject([something]); 别的 MyObject& ref= MyObject([something else]);

      【讨论】:

      • 你能解释一下为什么这比公认的答案更好吗?
      • 那么你就不能在if块的范围之外使用ref了。
      【解决方案11】:

      您可以使用在实际使用之前不需要初始化的模板。

        template <uint8_t c>
        uint8_t& ref; 
      void setup()
      {
        uint8_t a=1;
        uint8_t b=2;
      if(true) 
        ref<1> = a;
      else 
        ref<1> = b;
      }
      

      一些旧的 IDE 可能会将其标记为错误,但它会很好地通过编译。

      【讨论】:

        【解决方案12】:

        您可以使用“extern”关键字:第一次(假设在头文件中)您可以使用“extern”关键字在声明之前声明变量。稍后(在源文件中)您重复没有“extern”的声明并为其赋值。

        【讨论】:

        • 你试图回答什么问题?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-01
        • 1970-01-01
        • 2021-11-02
        • 1970-01-01
        • 2014-10-24
        相关资源
        最近更新 更多