【问题标题】:C++: References as return valuesC++:作为返回值的引用
【发布时间】:2011-04-15 15:08:05
【问题描述】:

我注意到当我不小心忘记从应该返回引用的函数返回时,我没有收到任何编译器错误。我写了一些小测试来看看实际发生了什么,我比什么都更困惑。

struct Foo
{
    int x;

    Foo() {
        x = 3;
    }
};

Foo* foo = new Foo;

Foo& test(bool flag) {
    if (flag)
        return *foo;
}

如果 test() 没有(明确地)返回值,我仍然会返回一些东西。然而,返回的 Foo 对象并未使用默认构造函数进行初始化——这是因为 x 在非显式返回值中与 3 不同。

当您不返回引用时实际发生了什么?如果这是一项功能,那么将其用作在发生错误时返回虚拟对象的方法是否安全,而不是返回空指针。 (请参见下面的示例。)

class FooFactory
{
    // Return reference...

    Foo& createFooRef() {
        Foo* foo = new Foo;
        bool success = foo->load();

        if (success)
            return *foo;
        // Implicit (and safe?) return value on failure?
    }

    // ... as opposed to returning a pointer.

    Foo* createFooPtr() {
         Foo* foo = new foo;
         bool success = foo->load();

         if (success)
             return foo;
         else
             return 0;
    }

    // Yes, I am aware of the memory leaks,
    // but that's not the point of the example.

【问题讨论】:

  • Microsoft 的 VC(Visual Studio 2010 Express 附带的那个,如果有影响的话)。

标签: c++ function reference return-value


【解决方案1】:

大多数编译器都会对此发出警告,但您可能必须提高编译器的警告级别才能看到它。

不,这不安全。这是坏的。仅返回当时发生在堆栈上的任何内容都可能导致堆栈损坏。正如您已经看到的,它确实为您使用构造函数。如果你想要一个默认构造的对象,你必须自己做(但要小心返回对临时对象的引用。这也很糟糕)。

【讨论】:

    【解决方案2】:

    在编译器中降低引用的常用方法是指针。对于一个引用返回函数,这意味着你得到一个任意的地址,无论是在寄存器或堆栈槽中用于返回值。

    在语言中,效果是未定义的。

    【讨论】:

      【解决方案3】:

      这是未定义的行为,可能会发生无限的坏事,或者确实可能不会发生,或者有时可能会发生,或者如果它不喜欢你,或者如果不喜欢你,或者从微软派工程师到你家,可能会同时发生但不会发生用棒球棒打你的头。

      【讨论】:

        【解决方案4】:

        所描述的行为不限于返回引用的函数。以下代码也将编译:
        int func1( int i )
        {
        if( i )
        return 3; // C4715 warning, nothing returned if i == 0
        }

        我不确定他们为什么只生成warning,而不是错误(设置中可能有一个选项可以将其变为错误),但如果你调用这样的函数,你会得到未定义的行为

        【讨论】:

          【解决方案5】:

          引用通常只是指针的语法糖,因此返回将从堆栈中获取指针的字节值作为返回值。如果你不给它它只会抓取垃圾。

          我不得不使用该函数,然后添加 -Wall 让 g++ 抱怨:

          g++ -Wall foo.cc foo.cc:在成员函数 'Foo& FooFactory::createFooRef()' 中: foo.cc:19: 警告:控制到达非空函数的结尾

          【讨论】:

            【解决方案6】:

            您是否尝试过使用 /O1 优化或更高版本进行编译并将警告视为错误?那可能会失败。我记得在 GCC 4.1 中发生了一些类似的事情。您可能会忘记在调试模式下返回引用,但引用会返回;只要您对其进行任何优化,它仍然会编译,但不会返回参考。在文本编辑器中编码时(就像我当时那样),这对我来说是一种完全的痛苦和巨大的惊喜。

            【讨论】:

              猜你喜欢
              • 2012-04-19
              • 2011-05-24
              • 1970-01-01
              • 2014-03-13
              • 2017-12-03
              • 1970-01-01
              • 2013-09-20
              • 1970-01-01
              • 2021-11-15
              相关资源
              最近更新 更多