C++ Взема адрес на временен - ​​грешка при присвояване на препратка към указател

Тази програма е написана на 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 в C++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, който инициализира полетата, включително copy-construction, деструктори за управление на динамичната памет, вероятно някои помощни функции за обхождане на списъка (или итератори за да можете да използвате алгоритми...) Просто не си правете труда и използвайте std::list.

person David Rodríguez - dribeas    schedule 13.02.2012
comment
По-скоро бих препоръчал vector като основна структура от данни, отколкото list. - person Matthieu M.; 13.02.2012