如何在C++中创建临时变量

use*_*458 4 c++ reference temporary

我有一个函数返回对我的类"记录"的实例的引用.

record& get_record(int key) {
    return lookup(key);
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,它返回一个引用而不是值.现在我稍微修改一下.

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.      
    }
}
Run Code Online (Sandbox Code Playgroud)

返回对局部变量的引用不是一个好主意是否正确?以及如何以一种临时变量的方式返回x?

son*_*yao 7

返回对局部变量的引用不是一个好主意是否正确?

是.离开函数时将破坏本地对象,因此返回的引用始终是悬空的.

你可以做x一个static变量.

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

请注意,返回的引用将始终引用同一个对象,即x.

  • 请不要编写编译但具有可怕隐藏后果的代码,而不至少在大而大胆的警告信息中指出这些后果."将始终引用相同的对象"只是没有"如果你两次调用函数你会在远处得到怪异的动作"或"这会让你获得数据竞争并将你的整个程序变成未定义的行为" ". (5认同)
  • 这当然是问你两次调用问题,即`Foo(get_record(1),get_record(2))`会创建两个对同一个`x`的引用. (4认同)
  • @SebastianRedl我可以理解数据竞赛,但是当你两次调用functiioin时,你的意思是什么"幽灵行动"?我知道它有潜在的问题,但它取决于OP的情况; 没有细节,我们无法提供更多特殊和完整的警告信息. (2认同)

YSC*_*YSC 6

这比一个坏主意更糟糕,它是未定义的行为并导致大多数情况发生崩溃.这很糟糕(TM).

您可以做的是更改返回类型,get_record以便返回智能指针.如果key有效,则返回一个指向它的观察者指针.否则,它返回一个拥有一个新创建的对象的智能指针:

#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
}
Run Code Online (Sandbox Code Playgroud)

1)关于[](record*){}:std::shared_ptr::shared_ptr()当智能指针被销毁时,作为第二个参数给出的这个no-op lambda 被调用.它取代了默认的删除操作,std::shared_ptr其行为是调用delete拥有的指针.


关于你的设计有缺陷的原因.事实上,将get_record返回作为参考使其不一致.你想要的是:

  • 如果key有效则返回对现有/永久对象的引用,和
  • 否则返回临时对象.

这两个是互斥的,你的功能没有意义:什么get_record回归语义?