声明引用并稍后初始化?

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

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

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

93521 次浏览

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

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]);

Short answer: you don't.

Marginally longer answer: do something like this:

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


MyObject& ref = getObject();

Usual disclaimers regarding references apply of course.

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

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.

MyClass *ptr;


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


MyClass &ref = *ptr;

You can use "extern" keyword: first time (assume, in header file) you can declare your variable preceding declaration with "extern" keyword. Later (in source file) you repeat declaration without "extern" and assign value to it.

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

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

I usually do this (C++ 11 or later):

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);

which is clean and allows using object definition with (possibly different) constructions, a thing you can't do directly with pointers as the compiler will complain from using temporary objects.

You can use a template which does not require initialization until you actually use it.

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

Some old IDEs may mark it as an error but it will finely pass the compilation.

use a static dummy as place holder. or std::optional with reference_wrapper.

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





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

I had a similar question, I solved it in a not so smart way. Question: I need declare a variable, its type is determined by element of "data"; the variable will be used outside the first if-condition, so it needs to be initialized outside the first if-condition.

wrong code:

Ivar& ref; // invalid, need init
if([condition]){
ref = data["info"];
if (ref.is_dict()) {
...
}
}
string x = ref["aa"];




  

Use a temp variable in condition

Ivar& ref = dict(); // Ivar and dict are faked; Ivar is interface variable
if([condition]){
Ivar& ref_tmp = data["info"];
if (ref_tmp.is_dict()) { // if the type of temp variable is correct
ref = ref_tmp  // assign ref_tmp to ref
...
}
}
string x = ref["aa"];