Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a temporary variable in C++

I have a function returning a reference to an instance of my class "record".

record& get_record(int key) {
    return lookup(key);
}

That is effective it returns a reference and not by value. Now I modify it a bit.

record& get_record(int key) {
    if (valid(key))
        return lookup(key);
    else {
        record x;
        x.valid=false;
        return x; //Here I really want to return a temporary variable
                  // and not a reference to a local variable.      
    }
}

Is it correct that returning a reference to a local variable is not a good idea? and how do I return x in such a way that it becomes a temporary variable?

like image 333
user2304458 Avatar asked Dec 08 '22 14:12

user2304458


2 Answers

Is it correct that returning a reference to a local variable is not a good idea?

Yes. The local object will be destroyed when get out of the function so the returned reference is always dangled.

You might make x a static variable.

record& get_record(int key) {
    if (valid(key))
        return lookup(key);
    else {
        static record x;
        x.valid=false;
        return x;
    }
}

Note that the returned reference will always refer to the same object, i.e. x.

like image 170
songyuanyao Avatar answered Dec 15 '22 10:12

songyuanyao


This is worse than a bad idea, it is undefined behavior and result in most of the cases to a crash. This is bad (TM).

What you could do is changing the return type of get_record so it returns a smart pointer. If key is valid, it returns an observer pointer to it. Otherwise, it returns an owning smart pointer to a freshly created object:

#include <memory>
#include <iostream>

struct record { int n; } some_record{42};

std::shared_ptr<record> get_record(bool b)
{
    if (b == true) {
        return std::shared_ptr<record>{&some_record, [](record*){}}; // see explanation ^1
    }
    return std::shared_ptr<record>{new record{0}};
}

int main()
{
    std::cout << get_record(true)->n << "\n";  // this is some_record
    std::cout << get_record(false)->n << "\n"; // this is a temporary
}

1) About [](record*){}: this no-op lambda given as the second argument to std::shared_ptr::shared_ptr() is invoked when the smart pointer is destroyed. It replaces the default deleter of std::shared_ptr whose behavior is to call delete on the owned pointer.


About why your design is flawed. In fact, making get_record return a reference makes it not consistent. What you want is:

  • if key is valid return a reference to an existing/permanant object, and
  • return a temporary object otherwise.

Those two are mutually exclusive, and your function doesn't make sense: what does get_record return semantically?

like image 40
YSC Avatar answered Dec 15 '22 09:12

YSC