С++ получение временного адреса - ошибка при назначении ссылки на указатель

Эта программа написана на C++. Я пытаюсь использовать функцию void для расширения структуры Line, состоящей из целочисленной длины и указателя на следующую подключенную строку. Существует функция void Expand, предназначенная для назначения ссылки на строку указателю строки в структуре. Новая строка должна быть в два раза больше текущей строки. С кодом, который я использую, я получаю ошибку g++ «Принимая адрес временного [-fpermissive]». Может ли кто-нибудь предложить способ, которым функция добавляет допустимый экземпляр ссылки на строку к указателю строки nextLine?

struct Line
{
    int length;
    Line* nextLine;
};

Line NewLine(Line& lineRef)
{
    Line newLine;
    newLine.length = lineRef.length * 2;
    return newLine;
}

void Expand(Line& lineRef)
{
    //Error here states: Taking address of temporary [-fpermissive]
    lineRef.nextLine = &NewLine(lineRef);
}

int main() {

    Line line;

    Expand(line);

    cout << line.length << endl;
    cout << line.nextLine->length << endl;

    return 0;
}

person Johnathan1    schedule 13.02.2012    source источник


Ответы (3)


Этот работает

    struct Line
    {
            int length;
            Line* nextLine;
            ~Line(){delete nextLine;}
             //Make copy constructor and assignment operator private
    };

    void Expand(Line* lineRef)
    {
            lineRef->nextLine = new Line;
            lineRef->nextLine->length = 2*(lineRef->length) ;
    }

int main() 
{

        Line* line = new Line;
        line->length = 5;

        Expand(line);

        cout << line->length << endl;
        cout << line->nextLine->length << endl;

        delete line;
        return 0;
}
person sank    schedule 13.02.2012
comment
Пожалуйста... не надо! Это не работает. Он похоже работает в этом образце игрушки, но произойдет ужасный сбой, если вы когда-либо скопируете Line, потому что будет скопирован указатель nextLine, но не содержимое, на которое он указывает, а затем среда выполнения попытается дважды вызвать delete по тому же указателю. - person Matthieu M.; 13.02.2012
comment
Да, конструктор копирования и оператор присваивания должны сделать глубокую копию или сделать их закрытыми. - person sank; 13.02.2012
comment
или, проще говоря, владение указателем должно быть передано умному указателю. std::unique_ptr в С++ 11. - person Matthieu M.; 13.02.2012
comment
@MatthieuM., я не совсем понимаю, как это будет работать. Не могли бы вы уточнить или опубликовать ссылку на пример? - person sank; 14.02.2012
comment
Почему бы не принять этот ответ за то, что он есть: простой фрагмент, который потребует дополнительного кода, прежде чем он станет полезным и стабильным (включая лучшую обработку копий). Хотя я предпочитаю другие ответы в качестве решения, это полезный ответ, который поможет оригинальному автору понять проблему, стоящую за его первоначальным вопросом. - person Darryl; 14.02.2012

Вы пытаетесь реализовать связанный список, но еще не понимаете ручного управления памятью.

Краткосрочное решение — использовать std::list<Line>. Уже есть работающее решение, и вам не нужно возиться с закулисными вещами.

Долгосрочное решение также заключается в использовании std::list<Line>. Не нужно заново изобретать велосипед, даже если вы опытный разработчик и знаете, как это сделать.

person MSalters    schedule 13.02.2012
comment
Я бы скорее рекомендовал vector в качестве базовой структуры данных, чем list. - person Matthieu M.; 13.02.2012
comment
@MatthieuM.: Потому что...? При отсутствии каких-либо требований к производительности, которые мы, конечно же, не можем вывести из фрагмента кода, найденного в вопросе, list‹› является таким же хорошим контейнером, как и vector‹›. - person Darryl; 14.02.2012
comment
@Darryl: Потому что Страуструп так сказал? vector – это по умолчанию выбор контейнера. Если у вас нет требований, указывающих на другую структуру данных, используйте файл vector. Он прост в использовании и предлагает большинство функциональных возможностей среди контейнеров Sequence, вплоть до C-совместимости (что важно для начинающих, поскольку, к сожалению, учебные пособия часто содержат отвратительное количество C-измов...) - person Matthieu M.; 14.02.2012
comment
Код из вопроса реализовал связанный список; Я не собирался это менять. Если бы это была проблема с Line[N], я бы рекомендовал std::vector. - person MSalters; 14.02.2012

Проблема с линией:

lineRef.nextLine = &NewLine(lineRef);

это то, что компилятор говорит вам. Вы берете адрес временного. Это означает, что после достижения ; временный NewLine(lineRef) будет уничтожен, а указатель lineRef.nextLine станет указателем на мертвый объект.


Обновление: как заставить это работать.

Это зависит от того, что вы хотите сделать. Если вы хотите иметь список, то проще всего использовать предварительно упакованную структуру данных list (std::list<Line>), а не создавать собственную реализацию списка.

Если вы действительно хотите реализовать свой собственный список, вам нужно будет динамически выделить следующий узел (это порадует компилятор) и вам нужно будет добавить код для управления списком (правильная конструкция объект Line, который инициализирует поля, включая копирующую конструкцию, деструкторы для управления динамической памятью, возможно, некоторые вспомогательные функции для обхода списка (или итераторы чтобы иметь возможность использовать алгоритмы...) Просто не заморачивайтесь и используйте std::list.

person David Rodríguez - dribeas    schedule 13.02.2012
comment
Я бы скорее рекомендовал vector в качестве базовой структуры данных, чем list. - person Matthieu M.; 13.02.2012