This is very similar to a question I asked earlier today. However, the example I cited in that question was incorrect; by mistake, I was looking at the wrong source file, not the one that actually had the error I described. Anyway, here's an example of my problem:
struct base { };
struct child1 : base { };
struct child2 : base { };
child1 *c1;
child2 *c2;
// Goal: iterate over a few derived class pointers using a range-based for loop.
// initializer_lists are convenient for this, but we can't just use { c1, c2 }
// here because the compiler can't deduce what the type of the initializer_list
// should be. Therefore, we have to explicitly spell out that we want to iterate
// over pointers to the base class.
for (auto ptr : std::initializer_list<base *>({ c1, c2 }))
{
// do something
}
This was the site of some subtle memory corruption bugs in my application. After experimenting a bit, I found that changing the above to the following made the crashes that I was observing go away:
for (auto ptr : std::initializer_list<base *>{ c1, c2 })
{
// do something
}
Note that the only change was an extra set of parentheses around the braced initializer list. I'm still trying to wrap my mind around all of the forms of initialization; am I right in surmising that in the first example, the inner braced initializer is a temporary that doesn't get its lifetime extended for the lifetime of the loop, due to the fact that it is an argument to the std::initializer_list
copy constructor? Based on this previous discussion of what the equivalent statement for the range-based for is, I think that's the case.
If this is true, then does the second example succeed because it uses direct list-initialization of the std::initializer_list<base *>
, and therefore the contents of the temporary braced list get their lifetime extended to the duration of the loop?
Aucun commentaire:
Enregistrer un commentaire