What's the lifetime of temporary objects in a range-for?
Consider this class:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foon";
}
typedef std::vector<std::string> Words;
const Words & words ()
{
return m_words;
}
private:
Words m_words = {"foo", "bar", "baz"};
};
Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:
for (auto w : Foo () .words ())
std::cout << w << "n";
But it wasn't
~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out
The standard is confusing me. Why is ~Foo
being called before the loop runs?
c++ c++11 for-loop temporary-objects
add a comment |
Consider this class:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foon";
}
typedef std::vector<std::string> Words;
const Words & words ()
{
return m_words;
}
private:
Words m_words = {"foo", "bar", "baz"};
};
Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:
for (auto w : Foo () .words ())
std::cout << w << "n";
But it wasn't
~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out
The standard is confusing me. Why is ~Foo
being called before the loop runs?
c++ c++11 for-loop temporary-objects
add a comment |
Consider this class:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foon";
}
typedef std::vector<std::string> Words;
const Words & words ()
{
return m_words;
}
private:
Words m_words = {"foo", "bar", "baz"};
};
Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:
for (auto w : Foo () .words ())
std::cout << w << "n";
But it wasn't
~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out
The standard is confusing me. Why is ~Foo
being called before the loop runs?
c++ c++11 for-loop temporary-objects
Consider this class:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foon";
}
typedef std::vector<std::string> Words;
const Words & words ()
{
return m_words;
}
private:
Words m_words = {"foo", "bar", "baz"};
};
Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:
for (auto w : Foo () .words ())
std::cout << w << "n";
But it wasn't
~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out
The standard is confusing me. Why is ~Foo
being called before the loop runs?
c++ c++11 for-loop temporary-objects
c++ c++11 for-loop temporary-objects
edited Jan 2 at 7:33
xeros
1068
1068
asked Jan 1 at 19:28
spraffspraff
18k1486167
18k1486167
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.
add a comment |
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "n";
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998307%2fwhats-the-lifetime-of-temporary-objects-in-a-range-for%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.
add a comment |
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.
add a comment |
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to
{
init-statementopt
auto &&__range = for-range-initializer ;
auto __begin = begin-expr ;
auto __end = end-expr ;
for ( ; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.
edited Jan 1 at 19:45
answered Jan 1 at 19:39
Werner HenzeWerner Henze
10.7k72854
10.7k72854
add a comment |
add a comment |
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "n";
add a comment |
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "n";
add a comment |
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "n";
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "n";
edited Jan 2 at 1:31
answered Jan 1 at 19:45
JansJans
9,02422635
9,02422635
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998307%2fwhats-the-lifetime-of-temporary-objects-in-a-range-for%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown