On Sat, Aug 03, 2019 at 07:29:34PM -0400, Sam Varshavchik wrote:
I believe that the following construct trips this assertion:
# std::vector<int> foo;
#
# std::vector<int> bar;
#
# // Populate foo with something.
#
# std::copy(&foo[0], &foo[foo.size()], std::back_insert_iterator{bar});
It's true that something like
copy(&foo[0], &foo[foo.size()], back_inserter(bar));
triggers an assertion when compiled with -D_GLIBCXX_ASSERTIONS. Because
the checking code just can't look at the context of its invocation.
Which is fine, because you really don't need to use such constructs.
There's nothing wrong with this. There is no out of bounds
access. I do not
believe that this is undefined behavior. The defined semantics of
std::vector, and its operator[], are well defined here.
It's defined behaviour but there is something wrong with it: it isn't
idiomatic C++ and it's tedious and error-prone.
I ran into these new assertions with my own code as well, after
updating to
F28 (where they were enabled by default the first time, IIRC, not sure why
this shows up only now, for that package).
I ended up tweaking my code to avoid the assertions, rather than disabling
them. For this particular situation, my original change was to try
std::copy(&foo[0], &foo[0]+foo.size(), std::back_insert_iterator{bar});
But that still tripped the assertion when the foo vector was empty, so I had
wrap this inside an if().
But why don't you use the idiomatic
copy(foo.begin(), foo.end(), back_inserter(bar));
?
No need to wrap it into an extra if statement.
With GCC, the generated code is basically the same as when using:
copy(foo.data(), foo.data()+foo.size(), back_inserter(bar));
vector::data() is available since C++11. This doesn't trigger
any assertion and works with an empty source vector, as well.
What also works in general and doesn't trigger any assertion is the
'ultra ugly':
copy(&*foo.begin(), &*foo.end(), back_inserter(bar));
But there is also really no need to use an back_insert_iterator here - a
direct solution:
bar.insert(bar.end(), foo.begin(), foo.end());
Best regards
Georg