-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Should ES.23 mention that ()-initialization is likely to be preferrable when dealing with containers containing types initializable from the container itself #2205
Comments
I am not sure about that.
I think |
Yes, sorry.
On the contrary, I think that what happens with What I'm saying is that it would beneficial if ES.23 mentioned that there are cases where preferring
Ok, to be more concrete, I had to update a class that looked like this, struct Foo {
Foo(v, /* other args */)
: v{}
, /* other init.ons */
std::vector<std::any> v;
// other member vars + API
}; where Later, the need arised for struct Foo {
Foo(v, /* other args */)
: v{std::move(v)}
, /* other init.ons */
std::vector<std::any> v;
// other member vars and member funcs
}; But this code is broken for the reason I explained, and it's not easy to debug because you just start seeing Another real-life case. Take this talk from Sean Parent about Runtime Polymorphism, where he always uses The result is that the code is bugged on lines 11-12, and the behavior is a neverending recursive call that stackoverflows. Making the ctor |
The same point is made in https://abseil.io/tips/88 |
"use the traditional constructor syntax when initialization is performing some active logic". |
I assure you that people write code like this all the time, and are surprised by it. I think they're right to be surprised that It's also surprising that compilers don't agree on this behaviour, because some refuse to implement what the standard says here. |
Thank you very much for the comments.
I hadn't considered the second vector didn't make its own copy of the first one. In that case, the data would be shared, if I am interpreting it and then deducing correctly, and it got me pondering. I have been experimenting trying to reproduce but haven't managed so far, this is what I get: #include <any>
#include <iostream>
#include <vector>
using std::any;
using std::any_cast;
using std::vector;
int main()
{
std::vector<std::any> v{1,2,3};
v[1] = 9;
std::vector<std::any> w{v};
std::cout << "w before reset:\n "
<< w.size() << ' '
<< w[0].has_value() << ' '
<< std::any_cast<std::vector<std::any>>(w[0]).size() << '\n' << " ";
//std::any_cast<std::vector<std::any>>(w[0])[1] = 7; // puzzling that the assignment doesn't seem to modify "w[0][1]"
v[1] = 7;
std::cout << any_cast<int>(any_cast<vector<any>>(w[0]).at(0)) << ' '
<< any_cast<int>(any_cast<vector<any>>(w[0]).at(1)) << ' '
<< any_cast<int>(any_cast<vector<any>>(w[0]).at(2)) << '\n';
w[0].reset();
std::cout << "w after reset:\n "
<< w.size() << ' '
<< w[0].has_value() << '\n';
//std::cout << std::any_cast<std::vector<std::any>>(w[0]).size() << '\n'; // compilation error, OK, it must cos of reset
std::cout << "v:\n "
<< v.size() << ' '
<< v[0].has_value() << ' '
<< v[1].has_value() << ' '
<< v[2].has_value() << '\n' << " ";
std::cout << any_cast<int>(v[0]) << ' '
<< any_cast<int>(v[1]) << ' '
<< any_cast<int>(v[2]) << '\n';
}
https://godbolt.org/z/ras68s6n6 From the result, I think that there is a copy: before the reset, the middle element in w is 9 and after the reset v still contains valid data and the middle element is 7. Perhaps is there an explanation related to the other comment on compilers and the standard? Interesting. I will continue taking a look and see what I figure out. |
I think you misunderstood. Obviously there's no data sharing between the vectors, that's not the point. My point is that for most types, But in the examples above, it makes a copy of |
Addressing the issue isocpp#2205 I opened myself. I can't see why not contributing.
Here's ES.23.
Should that mention that one might want to prefer
()
-initialization to{}
-initialization when initializing a container of elements of a given type from a container of the same type, when the inner type can be constructed from the vector itself?I'm referring to the fact that
will result in
w
having length 1, with its only elementv[0]
having been initialized fromv
. I think this can be surprising to most programmers.A similar scenario happens when, instead of
std::any
, the type inside the container has a templated constructor, like in this case.The text was updated successfully, but these errors were encountered: