// 错误的谓词实现方式, 对象含有堆上分配的数据成员,要格外注意,管好它。
template<> class Equal<const char*> {
public:
Equal(const char* data, EVarDim dim = EVarDim::exact)
: m_data(nullptr), m_dim(dim) {
m_data = new char[strlen(data) + 1];
strcpy_s(m_data, strlen(data) + 1, data);
}
~Equal() { delete[]m_data; }
bool operator()(const shared_ptr<SData>& rData) {
if (m_dim == EVarDim::exact)
return strcmp((const char*)(*rData).str, (const char*)m_data) == 0;
else
return strstr((const char*)(*rData).str, (const char*)m_data) != nullptr;
return false;
}
private:
char* m_data;
EVarDim m_dim;
};
void CDelete::RemoveName()
{
. . .
// 构造有名字的对象一次
Equal<const char*> equalName(in.InputName(m_list).c_str());
// 传递参数时,又通过拷贝构造出第一个匿名临时对象,并在该行调用完成后立即析构
m_list.remove_if(equalName);
. . .
// 构造有名字的对象二次
Equal<const char*> equalNameDim(in.InputName(m_list).c_str, EVarDim::dim);
// 传递参数时,又通过拷贝构造出第二个匿名临时对象,并在该行调用完成后立即析构
m_list.remove_if(equalNameDim.c_str());
. . .
} // 函数生命期结束,析构两个有名字的对象两次
// 两块内存被分别重复析构了2次,结果可想而知。蛋碎了。
// 提供简单拷贝构造函数的实现方式
template<> class Equal<const char*> {
public:
Equal(const char* data, EVarDim dim = EVarDim::exact)
: m_data(nullptr), m_dim(dim), m_iscopy(false) {
m_data = new char[strlen(data) + 1];
strcpy_s(m_data, strlen(data) + 1, data);
}
// 只要是副本,就让他们浅拷贝得了,反正他们先挂。只是,要给他们标记好标记即可。
Equal(const Equal& copy)
: m_data(copy.m_data), m_dim(copy.m_dim), m_iscopy(true) { }
~Equal() {
// 通过副本标记确定哪些对象才有资格析构自己的堆上数据
if (m_iscopy == false && m_data != nullptr)
delete[]m_data;
}
bool operator()(const shared_ptr<SData>& rData) {
if (m_dim == EVarDim::exact)
return strcmp((const char*)(*rData).str, (const char*)m_data) == 0;
else
return strstr((const char*)(*rData).str, (const char*)m_data) != nullptr;
return false;
}
private:
char* m_data;
EVarDim m_dim;
bool m_iscopy;
};
void CDelete::RemoveName()
{
. . .
Equal<const char*> equalName(in.InputName(m_list).c_str());
m_list.remove_if(equalName);
. . .
Equal<const char*> equalNameDim(in.InputName(m_list).c_str(), EVarDim::dim);
m_list.remove_if(equalNameDim);
. . .
}
// 最省心效率高的方法,直接用string对象
template<> class Equal<const string&> {
public:
Equal(const string& str, EVarDim dim = EVarDim::exact)
: m_str(str), m_dim(dim) {
}
bool operator()(const shared_ptr<SData>& rData) {
if (m_dim == EVarDim::exact)
return strcmp((const char*)(*rData).str, m_str.c_str()) == 0;
else
return strstr((const char*)(*rData).str, (const char*)m_str.c_str()) != nullptr;
return false;
}
private:
const string& m_str;
EVarDim m_dim;
};
void CDelete::RemoveName()
{
. . .
Equal<const string&> equalName(in.InputName(m_list));
m_list.remove_if(equalName);
. . .
Equal<const string&> equalNameDim(in.InputName(m_list), EVarDim::dim);
m_list.remove_if(equalNameDim);
. . .
}
上结果: