Question

My question is about optimizing the vector::erase function.

Since we know the vector is a continuous memory chunk and also know each element's size in the container, why does the vector<myclass> v's erase(v.begin()) method still call all the destructors of elements in v? Can it do a bytewise shift?

Example: Say you have

//compiled with g++ 4.7
#include<iostream>
using namespace std;
class barebone{
public:
  ~barebone(){
    cout << "1" << endl;
  }
};

int main(){
    vector<barebone> x(5);
    x.erase(x.begin());
    cout << "done" << endl;
}

This will call destructor for each elements in container (5 times). This will show 5 ones. a bytewise shift will be faster and call destructor only once

EDIT: From the reply erase() call destructor once with output

1 done 1 1 1 1

Was it helpful?

Solution

The destructor should only be called for the element(s) being erased; if you are seeing it called for the others, then your vector implementation isn't conformant. C++11 23.3.6.5 specifies

Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the move assignment operator of T is called the number of times equal to the number of elements in the vector after the erased elements.

Older standards specified similar behaviour, but with copy rather than move-assignment.

Your example shows 1 five times because the remaining destructors are called when the vector is destroyed at the end of main. You can see this more clearly if you output something immediately after the call to erase.

OTHER TIPS

I don't buy it. I wrote a test program, and after the erase the destructor is called only one time. I suggest that you do the same and see for yourself.

#include <iostream>
#include <vector>

using namespace std;

class TestObject
{
    public:
    static int counter;
    TestObject()  { std::cout << "constructed!" << std::endl; }
    ~TestObject() { std::cout << "destructed!" << std::endl; counter++;}
};

int TestObject::counter = 0;

int main()
{
   std::vector<TestObject> to(5);
   to.erase(to.begin());
   std::cout << "destructed " << TestObject::counter << " times" << std::endl;

   to.push_back(TestObject());

   return 0;
}

Here is the output.

Compiling the source code.... $g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program.... $demo constructed! constructed! constructed! constructed! constructed! destructed! destructed 1 times constructed! destructed! destructed! destructed! destructed! destructed! destructed!

Clearly, the destructor executed once after the erase. Now if you had the erase as the last thing followed by a cout in your own example it is possible that you thought that it was destroyed 5 times by the erase.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top