c ++ передает строковый литерал вместо const std :: string &? - PullRequest
7 голосов
/ 06 декабря 2010

У меня есть следующий код, который компилируется без предупреждений (-Wall -pedantic) с g ++

#include <iostream>
#include <string>

using namespace std;

class Foo
{
public:
    Foo(const std::string& s) : str(s)
    { }

    void print()
    {
        cout << str << endl;
    }

private:
    const std::string& str;
};


class Bar
{
public:

    void stuff()
    {
        Foo o("werd");
        o.print();
    }
};


int main(int argc, char **argv)
{
    Bar b;
    b.stuff();

    return 0;
}

Но когда я запускаю его, выводится только новая строка. Что происходит?

Если бы я делал это внутри:

string temp("snoop");
Foo f(temp);
f.print();

тогда все отлично работает!

Ответы [ 3 ]

21 голосов
/ 06 декабря 2010

Причина, по которой это терпит неудачу, заключается в том, что он по существу компилируется в следующее.

Foo o(std::string("wurd"));

В этом случае значение Foo принимает ссылку на временный объект, который удаляется после завершения конструктора. Следовательно, он держит мертвую ценность. Вторая версия работает, потому что она содержит ссылку на локальный ресурс, который имеет больший срок службы, чем экземпляр Foo.

Чтобы исправить это, измените значение memebr с const std::string& на const std::string.

2 голосов
/ 06 декабря 2010

Что происходит, так это то, что ссылка 'str' инициализируется так, что она указывает на временный аргумент 's'. Это почти то же самое, что и использование указателя - вы рассчитываете на постоянное существование вашего конструктора arg, 's'. Когда временный объект удаляется (после возврата из конструктора ftn), ваша ссылка теперь указывает на мусор.

Чтобы исправить, измените str так, чтобы он был действительным строковым объектом, а не ссылкой.

const std :: string str;

Таким образом, будет сделана копия вашей строки arg, и указанная копия будет иметь тот же срок жизни, что и ваш объект Foo.

0 голосов
/ 09 мая 2019

Расширение на ответы, данные ранее: Если вы хотите избежать копирования данных, вы можете изменить параметр член и конструктор Foo на const char*.

class Foo
{
public:
    Foo(const char* s) : str(s)
    { }

    void print()
    {
        cout << str << endl;
    }

private:
    const char* str;
};


class Bar
{
public:

    void stuff()
    {
        Foo o("werd");
        o.print();
    }
};


int main(int argc, char **argv)
{
    Bar b;
    b.stuff();

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...