Is it true that temporary objects are stored in dynamic (heap) memory?
The standard does not mandate any memory area (heap/stack) for them, but they are just like local variables "automatic storage", that is at the end of the expression (or longer when bound to a ref-to-const) they are destructed.
Most implementations will store them on the stack just like local variables.
edit:
As James Kanze pointed out: In the case the lifetime of a temporary is extended via a ref-to-const, its store location is on most implementations somewhat determined by the storage location of that reference. That is, in the case of the reference being in static storage, the temporary will be too (just confirmed on gcc). (although IMHO while this is still a temporary in the standards sense, it is arguable whether this is a temporary in the intuitive english sense of that word)
It depends on their lifetime. Temporaries you create inside of a function that you dont bind to a local static reference to lengthen their lifetime will most likely be created on the stack. Temporaries you bind to local static references will most likely be stored in the .data section of your program binary. Same holds for temporaries you bind to nonlocal references. Temporaries that are created during initialization of a nonlocal variable other that the one bound to by a reference should be on the stack of the function that produces the value of that nonlocal variable.
Exception objects that represent the thrown object during unwinding are temporaries too. Those usually reside on the heap.
This is highly implementation dependent, but they probably reside in automatic storage.
Note that the scope can be counter-intuitive, because of optimizations.
The following:
class A
{
//...
};
//....
A foo()
{
A a;
return a;
}
Here, the object a doesn't necessarily reside only inside the function's scope, but RVO can occur.
Also, when passing by value a temporary object, it might not get destructed immediately.
void foo(A a);
//...
foo( A() );
Here, a temporary is not necessarily only alive in that line, but can be constructed directly inside the method's argument stack.
Most (if not all) implementations store them on the stack (i.e. automatic storage), although I don't think the standard mandates anywhere. It's certainly easier to do it like that, as the compiler has to guarantee the temporary variable's life time, and it is possible that said lifetime will encompass a recursive call of the same function, creating another instance of the temporary variable.
Related
Is it true that temporary objects are stored in dynamic (heap) memory?
The standard does not mandate any memory area (heap/stack) for them, but they are just like local variables "automatic storage", that is at the end of the expression (or longer when bound to a ref-to-const) they are destructed.
Most implementations will store them on the stack just like local variables.
edit:
As James Kanze pointed out: In the case the lifetime of a temporary is extended via a ref-to-const, its store location is on most implementations somewhat determined by the storage location of that reference. That is, in the case of the reference being in static storage, the temporary will be too (just confirmed on gcc). (although IMHO while this is still a temporary in the standards sense, it is arguable whether this is a temporary in the intuitive english sense of that word)
It depends on their lifetime. Temporaries you create inside of a function that you dont bind to a local static reference to lengthen their lifetime will most likely be created on the stack. Temporaries you bind to local static references will most likely be stored in the .data section of your program binary. Same holds for temporaries you bind to nonlocal references. Temporaries that are created during initialization of a nonlocal variable other that the one bound to by a reference should be on the stack of the function that produces the value of that nonlocal variable.
Exception objects that represent the thrown object during unwinding are temporaries too. Those usually reside on the heap.
This is highly implementation dependent, but they probably reside in automatic storage.
Note that the scope can be counter-intuitive, because of optimizations.
The following:
class A
{
//...
};
//....
A foo()
{
A a;
return a;
}
Here, the object a doesn't necessarily reside only inside the function's scope, but RVO can occur.
Also, when passing by value a temporary object, it might not get destructed immediately.
void foo(A a);
//...
foo( A() );
Here, a temporary is not necessarily only alive in that line, but can be constructed directly inside the method's argument stack.
Most (if not all) implementations store them on the stack (i.e. automatic storage), although I don't think the standard mandates anywhere. It's certainly easier to do it like that, as the compiler has to guarantee the temporary variable's life time, and it is possible that said lifetime will encompass a recursive call of the same function, creating another instance of the temporary variable.
Let's take a look to this code:
A a(123);
new(&a) A(124);
Test says that in this case when program is shutting down destructor ~A() will called once. So if in A we has some pointers as fields we will get memory leak.
A a(123);
a.~A();
new(&a) A(124);
Here all will be correct. But according to standard using object after destructor calling is undefined behaviour(though mostly compilers provide behaviour without some troubles).
Can I take an address of object which destructor has been called?
Is calling placement new on stack variable is correct operation?
Can I take an address of object which destructor has been called?
[edited:]
Such an address is valid so if you have a pointer to it, it is valid.
Can you take its address after the fact, I am not fully sure.
basic.life.6 […] After the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object was located may be used but only in limited ways. […] Such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void* is well-defined.
Check out the full text for the all the restrictions, but use in placement-new is allowed.
As for the comments, I would argue both your samples are correct within the scope you showed.
A a(123);
new(&a) A(124);
I would argue this, given what we know in the sample, is correct.
Ending the lifetime of an object by re-using its storage is valid as per basic.life.5. Only condition is the program does not depend on side effects produced by the destructor - to be on the safe side I would only do that on trivially destructible types. Otherwise you need an explicit destructor call, like you did there:
A a(123);
a.~A();
new(&a) A(124);
I do not see any rule preventing that. The standard even explicitly mentions when such a construct is invalid:
If a program:
ends the lifetime of an object of type T with static, thread, or
automatic storage duration
and another object of the original type does not occupy that same
storage location when the implicit destructor call takes place,
the behavior of the program is undefined.
(formatting as bullet points mine)
Though not a definite proof, this passage suggests that in other cases, the behavior is defined. I cannot think of another rule that his would violate.
(Do note I use C++20 version of the standard)
Yes, this usage is valid. The storage for an object is independent from the object's lifetime.
By calling the destructor, you are ending the object's lifetime, but that does not mean that the storage is released.
According to the standard, that storage may be reused or released. And what you do is reusing it.
This exact case is well-defined in the standard in basic.life#8
Keep in mind that, because 'a' is a variable with automatic storage, at the end of the scope the destructor for that variable's type will be invoked.
In the following short example, what can be said about the object the pointer f points to or used to point to just before returning from main?
#include <vector>
struct foo {
std::vector<int> m;
};
int main()
{
auto f = new foo;
f->~foo();
}
I believe that there is no longer an object foo where f used to point. I've received a lot of comments that this may not be correct and that instead there could be an object foo in a destroyed, dead or otherwise invalid state.
What does the language standard have to say about the existence of an objects that is explicitly destroyed but whose storage is still valid?
In other words, can it reasonably be said that there is still an object at f that is outside of its lifetime? Is there such a thing as an object that is not in its lifetime, not begin constructed and not being destructed?
Edit :
It is clear that an object can exist when it isn't in its lifetime. During construction and destruction there is an object and its lifetime has not yet begun or as already ended. From https://timsong-cpp.github.io/cppwp/intro.object#1 :
[...] An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]). [...]
But after f->~foo(); the object that was pointed to by f (lets call it o) is not being constructed, it is not in its lifetime and it is not being destructed. My reading of this section is that o cannot occupy the storage anymore because it isn't in any of the enumerated situations. It seems like this implies that there is no o anymore and that there can't be a pointer to o anymore. By contradiction, if you had a pointer to o then that pointer would point to storage which o can't occupy.
Edit 2 :
If there isn't an object anymore, then what kind of value does foo have? It seems like the only sensible possible value it can have is a pointer to an object, which would contradict the statement. See this question.
In C++, objects essentially are eternal. There's nothing in the language that makes an object disappear. An object that is outside of its lifetime is still an object, it still occupies storage, and the standard has specific things that you can do with a pointer/reference to an object which is outside of its lifetime.
An object only truly goes away when it is impossible to have a valid pointer/reference to it. This happens when the storage occupied by that object ends its storage duration. A pointer to storage that is past its duration is an invalid pointer, even if the address itself later becomes valid again.
So by calling the destructor instead of using delete f (which would also deallocate the storage), f remains pointing to an object of type foo, but that object is outside of its lifetime.
The justification for my above statements basically boils down to the standard having none of the provisions that it would need in order to support the concept of objects being uncreated.
Where is object uncreation?
The standard provides clear, unequivocal statements about when an object comes to exist within a piece of storage. [intro.object]/1 outlines the exact mechanisms that provoke the creation of an object.
The standard provides clear, unequivocal statements about when an object's lifetime begins and ends. [basic.life] in its entirely outlines these things, but [basic.life]/1 in particular explains when an object's lifetime begins and ends.
The standard does not provide any statement (clear or otherwise) about when an object no longer exists. The standard says when objects are created, when their lifetimes begin, and when they end. But never does it say when they stop existing within a piece of storage.
There has also been discussion about statements of the form:
any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways.
Emphasis added.
The use of the past-tense suggests that the object is no longer located in that storage. But when did the object stop being located there? There is no clear statement about what exactly caused that to happen. And without that, the use of past-tense here just doesn't matter.
If you can't point to a statement about when it stopped being there, then the absolute most you can say is that there are a couple of places in the standard with wording that could be cleaned up. It doesn't undo the clear fact that the standard does not say when objects stop existing.
Pointer validity
But it does say when objects are no longer accessible.
In order for an object to cease existing, the standard would have to account for pointers which point to those objects when they no longer exist. After all, if a pointer is pointing to an object, then that object must still exist, right?
[basic.compound]/3 outlines the states that a pointer can have. Pointers can be in one of four states:
a pointer to an object or function (the pointer is said to point to the object or function), or
a pointer past the end of an object ([expr.add]), or
the null pointer value ([conv.ptr]) for that type, or
an invalid pointer value.
There is no allowance given for a pointer which points to no object. There is an allowance for an "invalid pointer value", but pointers only become invalid when the storage duration for the storage they point into ends:
When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values.
Note that this statement means that all pointers to such objects cease being in the "pointer to object" state and enter the "invalid pointer" state. Thus, objects within such storage (both within and outside of their lifetimes) stop being accessible.
This is exactly the sort of statement that would need to exist for the standard to support the concept of objects no longer existing.
But no such statement exists.
[basic.life] does have several statements that address limited ways that pointers to objects outside of their lifetime can be used. But note the specific wording it uses:
For an object under construction or destruction, see [class.cdtor]. Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.deallocation]), and using the pointer as if the pointer were of type void*, is well-defined.
It never says that the pointer "points to" allocated storage. It never undoes [basic.compound]/3's declaration about the kinds of pointers. The pointer is still a pointer to an object; it's just that the pointer "refers to allocated storage". And that the pointer can be used as a void*.
That is, there's no such thing as a "pointer to allocated storage". There is a "pointer to an object outside of its lifetime, whose pointer value can be used to refers to allocated storage". But is still a "pointer to an object".
Lifetime is not existence
Objects must exist in order to have a lifetime. The standard makes that clear. However, the standard does not at any point link the existence of an object to its lifetime.
Indeed, the object model would be a lot less complicated if ending the lifetime of an object meant that the object didn't exist. Most of [basic.life] is about carving out specific ways you can use the name of an object or a pointer/reference to it outside of the lifetime of that object. We wouldn't need that sort of stuff if the object itself didn't exist.
Stated in discussion about this matter was this:
I believe mentions of out-of-lifetime objects are there to account for objects that are being constructed and objects that are being destructed.
If that were true, what is [basic.life]/8 talking about with this statement:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object
If pointers to the original object become pointers to allocated memory when the object's lifetime ends, why does this statement talk about pointers to the original object? Pointers can't point to objects that don't exist because they don't exist.
This passage can only make sense if those objects continue to exist outside of their lifetimes. And no, it's not just about within the constructor/destructor; the example in the section makes that abundantly clear:
struct C {
int i;
void f();
const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C
While operator= does call the destructor, that destructor finishes before the this pointer is used. Thus, the special provisions of of [class.cdtor] does not apply to this at the moment the new object is created. So the new object is created outside of the destructor call to the old one.
So it's very clear that the "outside its lifetime" rules for objects are meant to always work. It's not just a provision for constructors/destructors (if it was, it would explicitly call that out). This means that names/pointers/references must still name/point-to/reference objects outside of their lifetime until the creation of the new object.
And for that to happen, the object they name/point-to/reference must still exist.
Names have scope (a compile-time property), while objects have lifetimes (a runtime property). Right?
I often see people talking about temporary objects "going out of scope". But since a temporary object does not have a name, I think it does not make sense to talk about "scope" in this context. The lifetime of a temporary object is very clearly defined and has nothing to do with scope. Would you agree?
Names have scope (a compile-time property),
Yes. I would not call it a property thought. But basically yes.
while objects have lifetimes (a runtime property). Right?
There are three types of variables. Each type has different properties in relation to lifetimes.
Automatic storage duration:
Static storage duration
Dynamic storage duration
Note: automatic storage duration objects have a lifetime that is bound to the scope of the variable.
I often see people talking about temporary objects "going out of scope".
Unless bound to a variable a temporary is destroyed at the end of an expression. If they are bound to a variable (a const reference) then they have the same lifespan as the variable. Sometimes it is just easier to refer to this as the scope, but technically you are correct.
But since a temporary object does not have a name, I think it does not make sense to talk about "scope" in this context.
Technically yes. But I think it just makes talking about it easier. To me (though not technically correct) the scope of a temporary (not bound) is the expression. Its easier to say than the lifespan of the temporary variable.
The lifetime of a temporary object is very clearly defined and has nothing to do with scope. Would you agree?
Yes. But it still feels more natural to talk about scope (even if it is not technically correct). As most people understand what you are trying to imply. But when you get down and talk about the very technical stuff you should use the correct terminology and scope in this context is not correct.
The lifetime of temporaries has very little to do with syntactical blocks, but "scope" — as a word rather than a technical term — can be used in other ways. The important question is whether you are confused when people use "scope" to refer to temporaries. (It doesn't appear that you are, from my POV.)
Since you're talking about using the term to communicate with others, that communication is what's really important. If you were defining terms by writing a standardese document or trying to interpret such a document in the context of defined terms, the situation would be different. Interpreting ISO 14882 will, of course, involve communicating with others, so you would just have to ask for clarification if necessary, in that case.
It's counter-productive to make all non-standardese communication be standardese, and it's often better to use code in either case when high precision is required. The C++ standard extensively uses examples for this reason.
For another example, "calling a constructor" is often used, yet technically you can't call a ctor directly; instead, ctors are part of object initialization. This is why there's an explicit form of new solely to construct an object. (Interestingly, you can call a destructor directly.) However, I would expect that phrase to be understood in most contexts, though I wouldn't advocate using it in standardese contexts.
I've seen people say that "an object went out of scope" when it meant (in your parlance) "the lifetime of the object ended when the object's name went out of scope". If you use that short form, it's natural to say that temporay objects go out of scope, too.
Temporary objects do have names, albeit referable by the compiler only. Otherwise how would the compiler refer to them? Just because you can't refer to a temporary once it's instantiated doesn't mean the compiler can't refer to it.
f(Foo(), Bar());
The compiler has to refer to at least one of the temporaries even though you as a programmer can't refer to either of them. Temporary objects do have a scope.
Binding to a const reference extends the lifetime of a temporary to the lifetime of the reference, so in a sense, it does have something to do with scope in this particular case :
std::string foo();
int main()
{
// Lifetime of the temporary returned by foo is indeed the scope of bar
const std::string &bar = foo();
}
See this article from Herb Sutter :
Normally, a temporary object lasts
only until the end of the full
expression in which it appears.
However, C++ deliberately specifies
that binding a temporary object to a
reference to const on the stack
lengthens the lifetime of the
temporary to the lifetime of the
reference itself, and thus avoids what
would otherwise be a common
dangling-reference error.
Suppose I have a C++ class with an attribute that is a reference:
class ClassB {
ClassA &ref;
public:
ClassB(ClassA &_ref);
}
Of course, the constructor is defined this way:
ClassB::ClassB(ClassA &_ref) : ref(_ref) { /* ... */ }
My question is: When an instance of class 'ClassB' is destroyed, is the object referenced by 'ClassB::ref' also destroyed?
A reference is nothing but an alias for a variable, the alias gets destructed, not the actual variable. You could consider it some kind of pointer, but there are reasons to refrain from this kind of (evil) thoughts :).
No. Reference members do not affect the lifetime of whatever they point to. This means the thing they alias may have a longer or a shorter lifetime than that of the reference.
On the other hand, const references can affect the lifetime of what they point to if they point to a temporary.
In your case it does not.
No. That's why you need a ~ClassB destructor if ClassB is responsible for the storage of ref which it might not be.
When an object is eliminated in C++, its memory is deallocated and thus everything that was embedded in it (such as member variables) is lost as well.
In the case of a pointer, the pointer is a member variable that contains an address, so the address is "destroyed" but the referenced object, if any, is not.
In the case of a reference member, the address is destroyed, but the target is not affected.
A class may define a destructor that could define special behaviors. One common such behavior is to invoke cleanup operations on members (if any), and to deallocate memory that was dynamically allocated earlier. Here, however, you already got an object so you should not be the one deallocating it.
No; references are merely an alternate syntax for pointers. The value they reference won't be modified if the reference is deallocated.
If you want it to be destroyed, you will have to encapsulate it (normally done via "smart" pointers, like std::shared_ptr or std::unique_ptr), that will automatically release the memory in an appropriate fashion on destruction of B. In-language references have no memory freeing behaviour associated with them, except the actual memory of the reference itself, as opposed to the referred.
You will have to build and understand your own memory model. People typically use shared_ptr and reference counting for basic uses.
I don't have the C++ spec on hand, but my guess is "No".
Pointers aren't deleted automatically when an object is destroyed, I see no reason that a reference should be different. Plus, having the reference automatically destroyed would be ripe for interesting bugs.