C
christophe (dot) poucet (at) gmail (dot) com
Hello,
I noticed there is a flaw in the vector implementation of g++ (3.4).
Basically when you erase an element from a vector, it calls the wrong
destructor. In most cases this is not such a big issue, but if one
were to store a class holding a resource, then the wrong resource would
be freed. Here is a test case to show what I mean: (Disregard the
destructors called for the temporaries).
#include <vector>
#include <iostream>
class A {
public:
A(int i) : i_(i) {
std::cout << "Making " << i_ << std::endl;
}
A(const A& other) : i_(other.i_) {
std::cout << "Making " << i_ << std::endl;
}
~A() {
std::cout << "Killing " << i_ << std::endl;
}
private:
int i_;
};
int main() {
std::vector<A> v;
v.push_back(A(1));
v.push_back(A(2));
v.push_back(A(3));
v.push_back(A(4));
std::cout << "Removing" << std::endl;
v.erase(v.begin()); // Should print "Killing 1"
std::cout << "Done Removing" << std::endl;
return 0;
}
The result is this:
---------------------------------------------------------
Making 1
Making 1
Killing 1
Making 2
Making 1
Making 2
Killing 1
Killing 2
Making 3
Making 1
Making 2
Making 3
Killing 1
Killing 2
Killing 3
Making 4
Making 4
Killing 4
Removing
Killing 4 <- FLAW, should be "Killing 1"
Done Removing
Killing 2
Killing 3
Killing 4
---------------------------------------------------------
Now of course, in this case it's rather pointless.. But in the case of
shared resources or smart pointers, this would lead to a crash (due to
wrong deallocation of 4 twice) and a memory leak (due to lack of
deallocation of 1, where there is a missing "Killing 1")
With regards,
Christophe
I noticed there is a flaw in the vector implementation of g++ (3.4).
Basically when you erase an element from a vector, it calls the wrong
destructor. In most cases this is not such a big issue, but if one
were to store a class holding a resource, then the wrong resource would
be freed. Here is a test case to show what I mean: (Disregard the
destructors called for the temporaries).
#include <vector>
#include <iostream>
class A {
public:
A(int i) : i_(i) {
std::cout << "Making " << i_ << std::endl;
}
A(const A& other) : i_(other.i_) {
std::cout << "Making " << i_ << std::endl;
}
~A() {
std::cout << "Killing " << i_ << std::endl;
}
private:
int i_;
};
int main() {
std::vector<A> v;
v.push_back(A(1));
v.push_back(A(2));
v.push_back(A(3));
v.push_back(A(4));
std::cout << "Removing" << std::endl;
v.erase(v.begin()); // Should print "Killing 1"
std::cout << "Done Removing" << std::endl;
return 0;
}
The result is this:
---------------------------------------------------------
Making 1
Making 1
Killing 1
Making 2
Making 1
Making 2
Killing 1
Killing 2
Making 3
Making 1
Making 2
Making 3
Killing 1
Killing 2
Killing 3
Making 4
Making 4
Killing 4
Removing
Killing 4 <- FLAW, should be "Killing 1"
Done Removing
Killing 2
Killing 3
Killing 4
---------------------------------------------------------
Now of course, in this case it's rather pointless.. But in the case of
shared resources or smart pointers, this would lead to a crash (due to
wrong deallocation of 4 twice) and a memory leak (due to lack of
deallocation of 1, where there is a missing "Killing 1")
With regards,
Christophe