The code is following:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct A {
A(int i = -1): i_(i) {
wcout << "Constructor: i = " << i_ << endl;
}
A(A const &a) {
wcout << "Copy constructor: i = " << i_ << " a.i = " << a.i_ << endl;
*this = a;
}
~A() { wcout << "Destructor: i = " << i_ << endl; }
A &operator=(A const& a) {
wcout << "Copy assignment operator: i = " << i_ << " a.i = " << a.i_ << endl;
i_ = a.i_;
return *this;
}
bool operator==(A const& rhs) { return i_ == rhs.i_; }
int get() { return i_; }
private:
int i_;
};
int wmain() {
A a[] = {1, 2, 3, 2, 4, 5};
vector<A> v(a, a + sizeof a/sizeof a[0]);
wcout << "==== Just before remove ====" << endl;
remove(v.begin(), v.end(), 2);
wcout << "==== Just after remove ====" << endl;
return 0;
}
Output:
==== Just before remove ====
Constructor: i = 2
Destructor: i = 2
Constructor: i = 2
Destructor: i = 2
Constructor: i = 2
Destructor: i = 2
Copy assignment operator: i = 2 a.i = 3
Constructor: i = 2
Destructor: i = 2
Constructor: i = 2
Destructor: i = 2
Copy assignment operator: i = 3 a.i = 4
Constructor: i = 2
Destructor: i = 2
Copy assignment operator: i = 2 a.i = 5
==== Just after remove ====
The question is: why destructor is called 6 times while remove() was running? I need this mess to be clarified.
NOTE: execute this code on your system, please, before answering.
NOTE: MSVCPP 11
In summary, the destructor calls have to do with the
2getting implicitly converted toAbyremove(). Every time the result of such an implicit conversion goes out of scope,A‘s destructor gets called.The reason for those implicit conversions is that
remove()needs to compare every element ofato2. The only way to do this is by callingA::operator==(const A&):Since
rhsis of typeconst A&, the compiler:A(int)to convert the2to anA;operator==(const A&);A::~A()to destroy the temporary.The latter are the destructor calls that you’re seeing.
If you were to add the following comparison operator to
A, you’ll see those destructor calls disappear:Alternatively, if you were to call
remove()like so, you’ll see all bar one destructor calls disappear:Finally, if you were to make
A::A(int)explicit, the compiler would not allow you to callremove()with2as the last argument (you’d have to call it withA(2)).