В моем коде scoped_ptr указывает на переменную стека - продлевает ли это время жизни переменной стека? - PullRequest
2 голосов
/ 06 сентября 2011

Я хотел бы знать, правильно ли сформирован следующий код

 if (  nChildLines == 0 ) 
 {
    nChildLines = 1;
    Tag tempTag = attachmentlines.tag();
    cfgChildLines = &tempTag;
 }

Здесь tampTag - это какой-то объект. И cfgChildLines - это ограниченный указатель на этот объект, объявленный вне блока if.

Теперь мой вопрос: когда блок 'if' завершается, разрушается ли tempTag? И если да, то использование 'cfgChildLines', которое указывает на tempTag, допустимо после конца блока if?

Ответы [ 3 ]

5 голосов
/ 06 сентября 2011

Важно помнить, что взятие адреса в C ++ НЕ гарантирует никакой защиты, что этот адрес продолжает указывать на что-то действительное. В язык не встроен подсчет ссылок (поэтому нам пришлось изобретать scoped_ptr / shared_ptr / etc).

Имея это в виду, мы можем более подробно рассмотреть вашу ситуацию:

tempTag является автоматической переменной и уничтожается в конце области ее создания. Поэтому адрес, который вы взяли, будет указывать где-то в стеке на уничтоженный объект вне этой области. Поскольку вы присвоили scoped_ptr, а scoped_ptr предполагает, что он может уничтожить объект посредством удаления, из документации

Шаблон класса scoped_ptr хранит указатель на динамически размещаемый объект

(акцент мой)

Итак, вы нарушаете интерфейс scoped_ptr и у вас будет некоторое неопределенное поведение после удаления scoped_ptr.

 {
    nChildLines = 1;
    Tag tempTag = attachmentlines.tag();
    cfgChildLines = &tempTag;
 } // tempTag destroyed here


// LATER
} // scoped_ptr calls delete, undefined behavior possibly crash, 
  // possibly an occasional crash

Если вам действительно нужен tempTag в большем объеме, просто объявите его в большем объеме, в котором он вам нужен, и не используйте scoped_ptr.

void Foo()
{
   Tag tempTag 

    {
        nChildLines = 1;
        tempTag = attachmentlines.tag();
    }
}

Еще один способ думать об этом: когда вы создаете динамически размещаемый объект, вы получаете право собственности на его время жизни. Вы вручную создаете и уничтожаете вещь. Поэтому вы можете передать это право собственности другому объекту, такому как scoped_ptr, который может управлять вашим делом. Напротив, переменные, созданные в стеке, будут автоматически выделяться и освобождаться - права на создание и удаление полностью принадлежат стеку вызовов, и вы не можете передать эти права себе или кому-либо еще (например, scoped_ptr). Вы можете стратегически размещать эти переменные только в том месте, которое правильно определяет область видимости переменной, чтобы автоматическое, основанное на стеке время жизни соответствовало тому, как вы намереваетесь использовать эту вещь.

2 голосов
/ 06 сентября 2011

Да, поскольку объект tempTag уничтожается, когда он выходит из области видимости в конце if, поэтому после if, cfgChildLines будет указывать на уничтоженный объект.

Вы можете использовать new, чтобы исправить это с наименьшим изменением существующего кода:

 if (  nChildLines == 0 ) 
 {
    nChildLines = 1;
    Tag* tempTag = new Tag(attachmentlines.tag());
    cfgChildLines = tempTag;
 }

Затем после if, cfgChildLines указывает на действительный Tag, который уничтожается, когда выходит из области видимости.

Также, как указывал Node, никогда не использует умный указатель на то, что не выделено new. В вашем примере вы указали умный указатель на выделенный стеку объект, который - даже если бы он имел более длительное время жизни - недопустим, потому что, когда умный указатель выходит из области видимости, он попытается delete выделенный объект стека и вызвать неопределенное поведение.

0 голосов
/ 11 января 2013

Вы спрашиваете:

& ldquo; это использование 'cfgChildLines', который указывает на tempTag, действительный после конца блока if? & Rdquo;

Нет, конечно, это не верно. У вас есть UB. Хватит это делать.


Примечание: Модератор SO Билл Ящер удалил мой предыдущий ответ, который был буквально таким же, предположительно потому, что он думал, что знает лучше.

в настоящее время принятое "решение" неверно, этот ответ правильный.

Это действительно раздражает, когда Word корректирует географию (изменяя «северо-восток» на «северо-запад»), а SO изменяет технические коррективы.

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