简体   繁体   中英

std::merge merging two std::vector coredump

the following code ends up with a core dump. What do I do wrong?

std::vector<int> a;
a.push_back(1);
a.push_back(4);
a.push_back(7);
std::vector<int> b;
b.push_back(2);
b.push_back(5);
b.push_back(8);
std::vector<int> c;
c.clear();


std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());
for (it=c.begin(); it!=c.end(); ++it)
    std::cout << *it << endl;

Is there any other merging function in the stl or in boost that I could be using?

Thanks!

The problem is that your c is empty because it was initialised with no elements, not to mention the unnecessary call to clear() . std::merge() takes an output iterator as its last argument. If c.begin() refers to the beginning of a std::vector that already contains enough elements, then this isn't a problem—those elements will just be overwritten. As it is, you're invoking undefined behaviour by writing values into memory past the end of the vector.

To ensure that c has enough space for the elements, you could do this:

c.resize(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), c.begin());

However, it is more idiomatic to use a std::back_insert_iterator , an output iterator that calls push_back() . For better efficiency, you can call reserve() on the vector beforehand. This ensures that c only needs to allocate memory once, rather than as it grows during the call to std::merge() . The final solution looks like this:

#include <iterator>

// ...

c.reserve(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));
std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));
                                                   ^^^^^^^^^^^^^^^^^^^^^^^

The thing is that if you pass c.begin() , the merge function will start writing values into *c.begin() , *(c.begin() + 1) etc, which leads to undefined behavior, including core dump. You have two options here.

  • Make sure c is large enough to hold all the values that merge is going to write into it. For example, you could call c.resize(a.size()+b.size()); prior to calling merge
  • Pass an std::back_insert_iterator . The example of it is given in the beginning on my answer. Every time you do *it = x where it is a back_insert_iterator , it will push_back x into the underlying container.

Info on back insert iterator can be found here . back_inserter is just a convenience function so that you don't write a lot of template arguments.

You're trying to store the results in c , which is empty, and as such, it doesn't have enough space to store them all (in fact, it doesn't have enough space to store anything ). Try to use back_insert_iterator , which will push_back the elements instead:

std::merge(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));

c isn't big enough to hold the merge. Try:

#include <iterator>
...
std::merge(a.begin(), a.end(),
           b.begin(), b.end(),
           std::back_inserter(c));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM