开发者

In my code scoped_ptr points to a stack variable -- does that extend the lifetime of the stack variable?

I wanted to know if the following code is well formed

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

Here, tampTag is some object. And cfgChildLines is a scoped pointer to that object declared outside o开发者_JS百科f the 'if' block.

Now my question is, when the 'if' block completes, does tempTag get destructed? And if so, is the usage of the 'cfgChildLines', which points to tempTag, valid past the end of the if block?


Important to remember that taking an address in C++ does NOT guarantee any protections that that address continues to point to something valid. There's no reference counting built into the language (thats why we had to invent scoped_ptr/shared_ptr/etc).

Keeping that in mind, we can look in more detail at your situation:

tempTag is an automatic variable and gets destroyed at the end of the scope it was created it. The address you took therefore will point somewhere on the stack to a destroyed object outside this scope. Since you assigned to a scoped_ptr, and scoped_ptr assumes it can destroy the object through delete, from the documentation

The scoped_ptr class template stores a pointer to a dynamically allocated object

(emphasis mine)

So you're violating scoped_ptr's interface and you're going to have some undefined behavior once the scoped_ptr is deleted.

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


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

If you really need tempTag in a larger scope, then just declare it in the larger scope you need it in and don't use scoped_ptr.

void Foo()
{
   Tag tempTag 

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

Another way to think about it: When you create a dynamically allocated object, you take ownership of its lifetime. You manually create and destroy the thing. Therefore you can pass this ownership to another object, such as a scoped_ptr which can manage things for you. In contrast, variables created on the stack will be automatically allocated and deallocated -- the rights to create and destroy are held entirely by the call stack and you can't give those rights to yourself or someone else (ie scoped_ptr). You can only strategically place those variables in a place that correctly scopes the variable so that the automatic, stack-based lifetime corresponds with how you intend to use the thing.


Yes, because the tempTag object is destroyed when it goes out of scope at the end of the if, so after the if, cfgChildLines would point to a destroyed object.

You can use new to fix that with the least modification to your existing code:

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

Then after the if, cfgChildLines points to a valid Tag, which is destroyed when it goes out of scope.

Also as Node pointed out, never use a smart pointer on something not allocated by new. In your example, you made a smart pointer point to a stack allocated object, which - even if it had a longer lifetime - is invalid because when the smart pointer goes out of scope, it will try to delete a stack allocated object and cause undefined behaviour.


You ask:

“is the usage of the 'cfgChildLines', which points to tempTag, valid past the end of the if block?”

No, of course it's not valid. You have UB. Stop doing that.


Note: The SO moderator Bill the Lizard deleted my previous answer which was literally the same, presumably because he thought he knew better.

The currently accepted "solution" is incorrect, this answer is correct.

It gets really annoying with Word correcting geography (changing "northeast" to "northwest") and SO mods correcting technical stuff.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜