When object constructed in argument is destructed, before of after function call?
E.g. is the following code safe?
void f(const char*)
{ ... }
std::string g()
{ ... }
...
f(g().c_str());
It always works for me but I don't know is it just undefined behaviour or it actually should work.
g() is a temporary. Lifetime of tempraries extends for the entire time of evaluation of the entire full-expression (in your case, that would be f(g().c_str())) Therefore your usage is safe, unless the f() stores the pointer somewhere.
§12.2/4 There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when an expression appears as an initializer for a declarator defining an object. In that context, the temporary that holds the result of the expression shall persist until the object’s initialization is complete. [...]
§12.2/5 The second context is when a reference is bound to a temporary. [...]
Neither of these two cases apply in your example.
A temporary object constructed as part of an expression evaluation is destructed after evaluating the full expression containing the expression, unless it is bound to a named reference. (12.2 and 1.9 in the current draft standard are the relevant sections).
So in your example, the temporary constructed to hold the return value of g will be destroyed after f returns.
It always works for me but I don't know is it just undefined behaviour
or it actually should work.
No, there is no undefined behavior because temporary object produced by g() will be deleted after evaluating full expression, that is body of f() function.
C++ Standard n3337 § 12.3/3
When an implementation introduces a temporary object of a class that has a non-trivial constructor (12.1,
12.8), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be
called for a temporary with a non-trivial destructor (12.4). Temporary objects are destroyed as the last step
in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true
even if that evaluation ends in throwing an exception. The value computations and side effects of destroying
C++ Standard n3337 § 12.3/4
There are two contexts in which temporaries are destroyed at a different point than the end of the full-
expression. The first context is when a default constructor is called to initialize an element of an array. If
the constructor has one or more default arguments, the destruction of every temporary created in a default
argument is sequenced before the construction of the next array element, if any.
C++ Standard n3337 § 12.3/5
The second context is when a reference is bound to a temporary. (...)
Related
This question already has answers here:
About binding a const reference to a sub-object of a temporary
(3 answers)
Closed 6 years ago.
It is known feature of C++ that a const reference extends the life time of the temporary object returned from a function, but is it acceptable to use constant reference to the member of the temporary object returned from the function?
Example:
#include <string>
std::pair<std::string, int> getPair(int n)
{
return {std::to_string(n), n};
}
int main(int, char*[])
{
const int x = 123456;
const auto& str = getPair(x).first;
printf("%d = %s\n", x, str.c_str());
return 0;
}
Output:
123456 = 123456
Yes, this code is perfectly acceptable. The rules, according to the standard are ([class.temporary]):
There are two contexts in which temporaries are destroyed at a
different point than the end of the fullexpression. The first context
is when a default constructor is called to initialize an element of an
array. If the constructor has one or more default arguments, the
destruction of every temporary created in a default argument is
sequenced before the construction of the next array element, if any.
The second context is when a reference is bound to a temporary. The
temporary to which the reference is bound or the temporary that is the
complete object of a subobject to which the reference is bound
persists for the lifetime of the reference...
As you can see the highlighted line makes it clear that binding reference to sub-objects is acceptable, as the complete object has to have its lifetime extended as well.
Note that first does qualify as a subobject [intro.object]:
Objects can contain other objects, called subobjects. A subobject can
be a member subobject (9.2), a base class subobject (Clause 10), or an
array element. An object that is not a subobject of any other object
is called a complete object.
It's well defined.
From the standard: $12.2/6 Temporary objects [class.temporary]:
(emphasis mine)
The temporary to which the reference is bound or the temporary that is
the complete object of a subobject to which the reference is bound
persists for the lifetime of the reference
And about the subobect, $1.8/2 The C++ object model [intro.object]:
(emphasis mine)
Objects can contain other objects, called subobjects. A subobject can
be a member subobject ([class.mem]), a base class subobject (Clause
[class.derived]), or an array element. An object that is not a subobject of any other object is called a complete object.
first is bound to reference and it's the member subobject of std::pair, so the temporary std::pair (i.e. the complete object) 's lifetime will be prolonged, the code should be fine.
For reference only: Clang and GCC say yes, VC says no.
As I mentioned in my comment:
The lifetime of the temporary should be prolonged as long as the
lifetime of its member access (str in this case). That said, you
should be just ok by taking return value by copy. RVO will avoid doing
extra copies.
From the standard, section 12.2.5:
The second context is when a reference is bound to a temporary. The
temporary to which the reference is bound or the temporary that is the
complete object of a subobject to which the reference is bound
persists for the lifetime of the reference except:
— A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits.
— A temporary bound to a reference parameter in a function call
(5.2.2) persists until the completion of the full-expression
containing the call.
To stay clear out of any trouble, I would rather do:
auto m_p = getPair(x);
This is as efficient as it can get because of RVO which every compiler must be doing for this case.
This seems addressed in 12.2/4-5:
There are two contexts in which temporaries are destroyed at a
different point than the end of the full expression. The first
context... [stuff dealing with arrays]
The second context is when a reference is bound to a temporary. The
temporary to which the reference is bound or the temporary that is the
complete object of a subobject to which the reference is bound
persists for the lifetime of the reference except:
There are four exceptions dealing with constructor binding of reference members, function calls, functions returning by reference, and references bound in new-initializers.
None of these cases apply, so the temporary is destroyed at the end of the full statement, leaving a dangling reference to a member of the temporary.
Just help the compiler realize it can move from the temporary: const auto str = std::move(getPair(x).first);
If I declare an object like this:
void main()
{
myclass objectA(anotherclass(true,true,0));
}
i.e. I create an objectA and another object "anotherclass" by directly calling the latter's constructor, what is "anotherclass"'s scope?
Does it get destructed only when main() finishes?
The temporary gets destructed at the end of the full expression that contains it, i.e. when the call to the constructor of myclass returns.
Per Paragraph 12.2/3 of the C++11 Standard:
Temporary objects are destroyed as the last step
in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true
even if that evaluation ends in throwing an exception. The value computations and side effects of destroying
a temporary object are associated only with the full-expression, not with any specific subexpression.
For this reason, if myclass's constructor takes an argument of type anotherClass by reference (either lvalue reference to const or rvalue reference), it shall not store it for future use, because it will be dangling if a temporary is passed, and dereferencing it would be Undefined Behavior.
It is only objectA that goes out of scope and gets destroyed when returning from the main() function.
The anotherclass object doesn't have a scope. Scope is a property of names, not of objects, and this object is not named. It's just a temporary object and will be destroyed at the end of the full expression.
Here's the definition of scope (§3.3.1):
In general, each particular name is valid only within some possibly discontiguous
portion of program text called its scope.
(I am aware of the fact that returning address/reference to a variable local to the function should be avoided and a program should never do this.)
Does returning a reference to a local variable/reference result in Undefined Behavior? Or does the Undefined Behavior only occur later, when the returned reference is used (or "dereferenced")?
i.e. at what exact statement (#1 or #2 or #3) does code sample below invoke Undefined Behavior? (I've written my theory alongside each one)
#include <iostream>
struct A
{
int m_i;
A():m_i(10)
{
}
};
A& foo()
{
A a;
a.m_i = 20;
return a;
}
int main()
{
foo(); // #1 - Not UB; return value was never used
A const &ref = foo(); // #2 - Not UB; return value still not yet used
std::cout<<ref.m_i; // #3 - UB: returned value is used
}
I am interested to know what the C++ standard specifies in this regard.
I would like a citation from the C++ standard which will basically tell me which exact statement makes this code ill-formed.
Discussions about how specific implementations handle this are welcome but as I said an ideal answer would cite an reference from the C++ Standard that clarifies this beyond doubt.
Of course, when the reference is first initialised it is done so validly, satisfying the following:
[C++11: 8.3.2/5]: There shall be no references to references, no arrays of references, and no pointers to references. The declaration of a reference shall contain an initializer (8.5.3) except when the declaration contains an explicit extern specifier (7.1.1), is a class member (9.2) declaration within a class definition, or is the declaration of a parameter or a return type (8.3.5); see 3.1. A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field. —end note ]
The reference being returned from the function is an xvalue:
[C++11: 3.10/1]: [..] An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ] [..]
That means the following does not apply:
[C++11: 12.2/1]: Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5).
[C++11: 6.6.3/2]: A return statement with neither an expression nor a braced-init-list can be used only in functions that do not return a value, that is, a function with the return type void, a constructor (12.1), or a destructor (12.4).
A return statement with an expression of non-void type can be used only in functions returning a value; the value of the expression is returned to the caller of the function. The value of the expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy or move of a temporary object (12.2). [ Note: A copy or move operation associated with a return statement may be elided or considered as an rvalue for the purpose of overload resolution in selecting a constructor (12.8). —end note ] A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization (8.5.4) from the specified initializer list. [ Example:
std::pair<std::string,int> f(const char* p, int x) {
return {p,x};
}
—end example ]
Additionally, even if we interpret the following to mean that an initialisation of a new reference "object" is performed, the referee is probably still alive at the time:
[C++11: 8.5.3/2]: A reference cannot be changed to refer to another object after initialization. Note that initialization of a reference is treated very differently from assignment to it. Argument passing (5.2.2) and function value return (6.6.3) are initializations.
This makes #1 valid.
However, your initialisation of a new reference ref inside main quite clearly violates [C++11: 8.3.2/5]. I can't find wording for it, but it stands to reason that the function scope has been exited when the initialisation is performed.
This would make #2 (and consequently #3) invalid.
At the very least, there does not appear to be anything further stated about the matter in the standard, so if the above reasoning is not sufficient then we have to conclude that the standard is ambiguous in the matter. Fortunately, it's of little consequence in practice, at least in the mainstream.
Here's my incomplete and possible insufficient view on the matter:
The only thing special about references is that at initialization time they must refer to a valid object. If the object later stops existing, using the reference is UB, and so is initializing another reference to the now-defunct reference.
The following much simpler example provides exactly the same dilemma as your question, I think:
std::reference_wrapper<T> r;
{
T t;
r = std::ref(t);
}
// #1
At #1, the reference inside r is no longer valid, but the program is fine. Just don't read r.
In your example, line #1 is fine, and line #2 isn't -- that is because the original line #2 calls A::A(A const &) with argument foo(), and as discussed, this fails to initialize the function argument variable with a valid reference, and so would your edited version A const & a = foo();.
I would say #3. Alone, #2 doesn't actually do anything even though the referenced object is already out of scope. This isn't really a standards-related issue because it is the result of two mistakes made in succession:
Returning a reference to an out-of-scope object followed by
Use of a reference.
Either in isolation has defined behavior. Whether the standard has anything to say regarding use of references to objects beyond the end of their lifetime is another matter.
Is the order of execution of the three commented lines below guaranteed?
struct S
{
S() { /* called 1st */ }
~S() { /* called 3rd */ }
};
boost::shared_ptr<S> f()
{
return boost::shared_ptr<S>(new S);
}
int second() { return 0; /* called 2nd */ }
int test()
{
return (f(), second());
}
With my compiler, the shared_ptr returned by f() seems to persist until after second() is called. But is this guaranteed by the standard and thus other compilers?
Yes.
Temporaries persist until the completion of the full-expression.
[n3290: 12.2/3]: When an implementation introduces a temporary
object of a class that has a non-trivial constructor (12.1,
12.8), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with
a non-trivial destructor (12.4). Temporary objects are destroyed as
the last step in evaluating the full-expression (1.9) that (lexically)
contains the point where they were created. This is true even if that
evaluation ends in throwing an exception. The value computations and
side effects of destroying a temporary object are associated only with
the full-expression, not with any specific subexpression.
And:
[n3290: 1.9/10]: A full-expression is an expression that is not a
subexpression of another expression. If a language construct is
defined to produce an implicit call of a function, a use of the
language construct is considered to be an expression for the purposes
of this definition. A call to a destructor generated at the end of the
lifetime of an object other than a temporary object is an implicit
full-expression. Conversions applied to the result of an expression in
order to satisfy the requirements of the language construct in which
the expression appears are also considered to be part of the
full-expression. [..]
This means that both f() and second() should exist until execution returns from test() with the result of evaluating the latter.
This may sound naive. I want to know what happens when i explicitly call a constructor like this:
class A{
/*...*/
public:
A(){}
};
int main(){
A();
return 0;
}
Is a useless object created which remains in the memory until the scope of main() ends?
You create an object that lasts until the end of the statement.
Its considered a nameless temporary which gets destroyed after the end of the full expression. In this case, the point right after the semicolon. To prove this, create a destructor with a print statement.
when i explicitly call a constructor like this
You are not calling a constructor here; but creating a temporary object which gets destructed immediately. Constructor can be called explicitly with an object of that type (which is not advisable).
Is a useless object created which remains in the memory until the
scope of main() ends?
It doesn't have scope till the function ends, but till the ; ends.
Strictly speaking you can never make a direct call to a constructor in C++. A constructor is called by the implementation when you cause an object of class type to be instantiated.
The statement A(); is an expression statement and the expression is a degenerate form of an explicit type conversion (functional notation). A refers to the type, strictly speaking constructors don't have names.
From the standard (5.2.3 [expr.type.conv] / 2:
The expression T(), where T is a simple-type-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized [...].
Because your class type has a user-declared default constructor the value-initialization of this temporary will use this constructor. (see 8.5 [dcl.init]/5)
Okay, I re-visited temporary and found that in the above example, it's actually a part of expression that is initializing an object. So yes, the scope ends at ;
Here:
When a temporary object is created to initialize a reference variable, the name of the temporary object has the same scope as that of the reference variable. When a temporary object is created during the evaluation of a full-expression (an expression that is not a subexpression of another expression), it is destroyed as the last step in its evaluation that lexically contains the point where it was created.