Почему внешний указатель на строковый литерал теряется при выходе из области видимости? (C ++)

В следующей программе:

#include <string>
#include <deque>
#include <assert.h>

struct Foo {
    // member var
    const std::string *m_pstr;

    // ctor
    Foo (const std::string *pS) : m_pstr (pS) {}

    // copy ctor
    Foo (const Foo& other) : m_pstr (other.m_pstr) {}

    // swap
    void swap (Foo &other) { std::swap (m_pstr, other.m_pstr); }

    // assignment operator
    Foo& operator=(Foo tmp)
    {
        this->swap (tmp);
        return *this;
    }

    // dtor
    ~Foo () {}
};


struct FooQueue {
    // member var
    std::deque<Foo> m_q;

    void Enqueue (const Foo &f)
    {
        m_q.push_back (f);
        assert (*(m_q.front().m_pstr) == std::string("Hello")); // This Passes
    }

    void Enqueue (const std::string &s)
    {
        Foo f (&s);
        Enqueue (f);
        assert (*(m_q.front().m_pstr) == std::string("Hello")); // This Passes
    }
};


void ProcessEvent (FooQueue &fq)
{
    fq.Enqueue ("Hello");
    assert (*(fq.m_q.front().m_pstr) == std::string("Hello"));  // This Fails
}


int main (int argc, char* argv[])
{
    FooQueue fq;
    ProcessEvent (fq);
    return 0;
}

утверждение в функции ProcessEvent () терпит неудачу, и я не знаю почему. Я ожидаю, что строковый литерал «Hello» в аргументе fq.Enqueue () сохранится через изменения в области видимости (из-за this), и я ожидал, что указатель члена m_pstr также продолжит указывать на этот строковый литерал через изменения в области видимости. Может кто меня просветить?


person sifferman    schedule 19.11.2014    source источник
comment
Строковый литерал типа const char[6] сохраняется, но неявно преобразованное rvalue std::string не сохраняется.   -  person PeterT    schedule 19.11.2014


Ответы (2)


В этом случае будет создан временный строковый объект для хранения «Hello». Затем этот временный объект привязан к строковому объекту s.

void Enqueue (const std::string &s)

Это означает, что время жизни временного расширяется до объема строки s. Однако, когда эта функция завершится, s будет уничтожен.

Итак, в ProcessEvent эта строка давно исчезла.

person ravi    schedule 19.11.2014
comment
Да! конечно. Итак, я ошибался в предположении, что время жизни std :: string (Hello) было таким же, как у статического Hello. Спасибо всем, кто дал правильные ответы. - person sifferman; 19.11.2014

Вы вводите в очередь временный std::string, преобразованный из буквенного "Hello". Временный объект будет уничтожен после вызова fq.Enqueue(), и ваша очередь будет ссылаться на удаленный объект.

person kuroi neko    schedule 19.11.2014