Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declare a reference and initialize later?

Tags:

c++

reference

I have a reference to some class MyObject, but the exact object depends on a condition. I want to do something like this:

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

I cannot do this right now because the compiler does not allow me to declare but not initialize a reference. What can I do to achieve my goal here?

like image 893
user1861088 Avatar asked Feb 14 '13 19:02

user1861088


People also ask

Can we declare a reference variable without initializing it?

A reference can be declared without an initializer: When it is used in a parameter declaration. In the declaration of a return type for a function call. In the declaration of class member within its class declaration.

How do you initialize a reference variable?

There are three steps to initializing a reference variable from scratch: declaring the reference variable; using the new operator to build an object and create a reference to the object; and. storing the reference in the variable.

Do references need to be initialized?

You must always be able to assume that a reference is connected to a legitimate piece of storage. Once a reference is initialized to an object, it cannot be changed to refer to another object. Pointers can be pointed to another object at any time. A reference must be initialized when it is created.

Can we declare a reference variable without initializing it in C++?

In C++, you can't declare a reference without initialization. You must initialize it.


4 Answers

You need to initliaze it. But if you would like to conditionally initialize it, you can do something like this:

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]); 
like image 157
Zaffy Avatar answered Oct 13 '22 05:10

Zaffy


AFAIK this can't be done with a reference. You'd have to use a pointer:

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

The pointer will act similar to a reference. Just don't forget to use -> for member access.

like image 27
David G Avatar answered Oct 13 '22 04:10

David G


You can't do this. References must be bound to something, you may not like it but it prevents a whole class of errors, because if you have a reference you can always assume it's bound to something, unlike a pointer which could be null.

Your example code wouldn't work anyway because you attempt to bind a non-const reference to a temporary object, which is invalid.

Why do you need it to be a reference anyway? One solution would be to ensure your type has an inexpensive default constructor and can be efficiently moved, then just do:

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

Otherwise you'd have to put the conditional code in one or more functions, either:

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

or

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

Note that both these versions use a const reference, which can bind to a temporary, if the object must be non-const, then again stop trying to use a reference:

MyObject obj = createObject([condition]);

This will probably be just as efficient as what you were trying to do, thanks to the return value optimization

like image 26
Jonathan Wakely Avatar answered Oct 13 '22 05:10

Jonathan Wakely


What I like to do is a lambda that's immediately executed.

Let's suppose we want a const std::string& to a variable from under the map - if map does not contain given key - we want to throw.

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.
}

You could also use std::invoke() to make it more readable (since 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.
    }
  });
}
like image 38
Latawiec Avatar answered Oct 13 '22 06:10

Latawiec