这个const引用是否保留了它的生命?

时间:2017-05-31 20:34:46

标签: c++

我找到问题this answer"Does a const reference prolong the life of a temporary?",其中指出:

  

只有本地 const引用会延长使用寿命。

我担心自己的标准是不能直接知道下面的foo是否是本地const引用。

下面的const std::string& foo是否会延长在std::string调用中创建的临时get_or函数参数的生命周期,或者我是否有悬空引用?

#include <iostream>
#include <boost/optional.hpp>

struct Foo
{
    const std::string& get_or(const std::string& def)
    {
        return str ? str.get() : def;
    }

    boost::optional<std::string> str;
};

int main()
{
    Foo f;
    const std::string& foo = f.get_or("hello world");

    std::cout << foo << '\n';
}

3 个答案:

答案 0 :(得分:4)

在这种情况下,

const&不会延长生命周期。考虑构造临时的example here然后尝试打印它:它使用与您的代码相同的构造,但我已经对其进行了更改以使对象构造和销毁对用户更明确。

#include <iostream>

struct reporting {
    reporting() { std::cout << "Constructed" << std::endl;}
    ~reporting() { std::cout << "Destructed" << std::endl;}
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;}
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;}
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;}
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;}

    void print() const {std::cout << "Printing." << std::endl;}
};

const reporting& get_or(const reporting& def)
{
    return def;
}

int main()
{
    const reporting& foo = get_or(reporting{});

    foo.print();
    return 0;
}

输出:

Constructed
Destructed
printing.

注意在显示printing.之前对象是如何被销毁的。

您可能想知道为什么代码仍然完成且没有可见错误:它是未定义行为的结果。有问题的对象不存在,但由于它不依赖于状态来调用其方法,因此程序不会崩溃。其他更复杂的例子不能保证这不会导致崩溃或导致其他意外行为。

顺便提一下,如果临时是bound directly to the const&

,情况会有所不同
#include <iostream>

struct reporting {
    reporting() { std::cout << "Constructed" << std::endl;}
    ~reporting() { std::cout << "Destructed" << std::endl;}
    reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;}
    reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;}
    reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;}
    reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;}

    void print() const {std::cout << "printing." << std::endl;}
};

const reporting& get_or(const reporting& def)
{
    return def;
}

int main()
{
    const reporting& foo = reporting{};

    foo.print();
    return 0;
}

输出:

Constructed
printing.
Destructed

查看对象在使用之后是如何销毁的。在这种情况下,对象会一直存在,直到范围结束。

答案 1 :(得分:2)

你通过太多的引用传递了字符串。

将临时字符串绑定到def get_or参数将字符串的生命周期延长到包含函数调用的完整表达式的末尾,但将def绑定到返回值get_or并将get_or的返回值绑定到foo不会进一步延长生命周期。当你尝试打印时,字符串已经死了。

答案 2 :(得分:1)

&#34;临时&#34;有问题的是std::string - 在使用get_or类型的参数调用const char*时创建的对象。此临时对象的生命周期受函数get_or的结束限制,并且您返回对此临时对象的引用并在之后分配它的事实不会延长生命周期。请参阅以下代码,该代码使用简单的&#34; custom&#34;字符串类,cout的构造和破坏:

class MyString {
public:
    MyString (const char* str) {
        m_str = strdup(str);
        cout << "constructor MyString - '" << m_str << "'" << endl;
    }
    ~MyString() {
        cout << "destructor MyString - '" << m_str << "'" << endl;
        free(m_str);
    }
    char *m_str;
};

struct Foo
{
    const MyString& get_or(const MyString& def)
    {
        cout << "Foo::get_or with '" << def.m_str << "'" << endl;
        return def;
    }
};

int main()
{
    Foo f;
    const MyString& foo = f.get_or("hello world");
    cout << "usage of foo?" << endl;
}

输出:

constructor MyString - 'hello world'
Foo::get_or with 'hello world'
destructor MyString - 'hello world'
usage of foo?

请注意,在您有机会使用foo之前调用析构函数。

如果直接为临时分配引用,则情况会有所不同。同样,生命周期一直持续到函数main的结尾,但它将在main中使用,而不是在任何调用main的函数中使用:

const MyString& foo2 = MyString("hello world2");
cout << "usage of foo..." << endl;

然后输出将是:

constructor MyString - 'hello world2'
usage of foo...
destructor MyString - 'hello world2'