删除重复项
C++, Remove duplicate items
这段代码有什么问题?我正在尝试从用户定义的容器中删除重复元素。
template <typename Item>
struct TList
{
typedef std::vector <Item> Type;
};
template <typename Item>
class GenericContainer
{
protected:
typename TList <Item>::Type items;
};
有一个方法可以删除容器中专门为Item *(即项目是动态分配的)的重复元素:
template <typename Item>
template <typename Sort, typename Equal>
void Container <Item * >::remove ( typename TList <Item *>::Type ::iterator it_begin, typename TList <Item *>::Type ::iterator it_end, Sort sort, Equal equal )
{ //Sort items, ok
std::sort ( it_begin, it_end, sort );
//Apply unique, OK
typename TList <Item *>::Type ::iterator i_new_end = std::unique ( it_begin, it_end, equal );
//Delete items after new end of container, OK
for (typename TList <Item *>::Type ::iterator i_item = i_new_end ; i_item != it_end; i_item ++)
{
delete *i_item; //call destructor
}
//Erase duplicate items
this->items.erase ( i_new_end, it_end );
//Another sort, Exception: Acces in free memory
std::sort ( it_begin, i_new_end, sort );
);
我不能在行中找到问题
//Another sort, Exception: Acces in free memory
std::sort ( it_begin, i_new_end, sort );
或…之前的行
Error log:
Access in freed memory in process: sw.exe(line 796)
谢谢你的建议。
更新问题:
我用另一个编译器(MSVS 2010)翻译代码并检查向量项。以下是结果:
输入数据集:628项。
A) std::sort ( it_begin, it_end, sort );
628件
B) typename TList <Item *>::Type ::iterator i_new_end = std::unique ( it_begin, it_end, equal );
612个唯一条目
C) for (typename TList <Item *>::Type ::iterator i_item = i_new_end ; i_item != it_end; i_item ++)
{
delete *i_item; //call destructor
}
令我惊讶的是条目[595]之后的条目被删除了(为什么不删除条目[613]??)我不理解这种奇怪的行为……
我敢打赌,不仅一些值出现了不止一次,一些单独的对象在序列中出现了不止一次。
当您delete
所有重复的值时,您将销毁序列中保留的一些对象。
第二次排序(这是不必要的,因为unique
在删除重复项时不会重新排列东西)访问每个对象,因此它立即步进那些只是delete
d的对象。
一个可能的解决方案是sort
两个范围内的指针由unique
产生。使用set_difference( i_new_end, it_end, i_begin, i_new_end, i_sequence_inserter )
来找到真正需要被释放的对象——假设它们在其他地方没有被使用。
或者,只使用智能指针,或者根本不使用指针:v)。
编辑:
请参阅我的注释——最好的解决方案可能是完全消除指针的使用。
无论如何,这里是一个set_difference
解决方案的示例,这个示例使用自定义迭代器而不是序列插入器。
template <typename Item>
template <typename Sort, typename Equal>
void Container <Item * >::remove ( typename TList <Item *>::Type ::iterator it_begin, typename TList <Item *>::Type ::iterator it_end, Sort sort, Equal equal )
{ //Sort items, ok
std::sort ( it_begin, it_end, sort );
//Apply unique, OK
typename TList <Item *>::Type ::iterator i_new_end = std::unique ( it_begin, it_end, equal );
// Now sort the sub-ranges on pointer values to identify duplicate pointers
std::sort( it_begin, i_new_end );
std::sort( i_new_end, it_end );
// delete all pointers that appear only in the set of duplicate values to be erased
struct deleter {
deleter &operator *() { return *this; } // assignment to target is assgn. to iter
deleter &operator =( Item *rhs ) { delete rhs; return *this; }
deleter &operator ++() { return *this; } // increment is no-op
deleter &operator ++(int) { return *this; } // increment is no-op
};
std::set_difference( i_new_end, it_end, it_begin, i_new_end, deleter() );
//Erase duplicate items
this->items.erase ( i_new_end, it_end );
//Another sort, Exception: Acces in free memory
std::sort ( it_begin, i_new_end, sort );
);
听起来上次调用std::sort
时使用的迭代器可能无效。可能是it_begin
。你可以尝试使用this->items.begin()
代替吗?
在我看来,传入的迭代器实际上不是来自this->items
,而是来自其他容器。
另一种可能性是delete *i_item
引起了问题,它只在最后一行显示为延迟反应。
编辑:另一个出现的方式比你期望的更频繁的选项是,你的sort
谓词不遵守严格的弱排序。你能出示一下密码吗?
经过一点测试,我认为i_new_end
被.erase()
调用无效。
根据文档,它应该仍然是有效的——只有i_new_end之后的指针应该是无效的。但visualc++显然不遵循这一点。它几乎做了正确的事情,i_new_end和end()都指向内存中的相同位置,但是_Mycont
对于i_new_end
被重置为零,这使指针无效。
也就是说,即使它们指向相同的地址,这也失败了:
if (i_new_end._Myptr == end()._Myptr) // yes, they're the same
if (i_new_end == end()) // boom. exception
那么,试试这个:
// remember next-to-last item
typename TList <Item *>::Type ::iterator nextlast = i_new_end - 1;
//Erase duplicate items
this->items.erase ( i_new_end, it_end );
// reset i_new_end
i_new_end = nextlast + 1;
// Now this line should not throw
std::sort ( it_begin, i_new_end, sort );
还要记住Potatoswatter提到的内存问题。
- 将数组的地址分配给变量并删除
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C/C++编译器通常会删除重复的库吗
- 从链接列表c++中删除一个项目
- C++如何通过用户输入删除列表元素
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 使用函数"remove"删除重复元素
- 如何从多映射中删除特定的重复项
- 运算符C++ "delete []"仅删除 2 个前值
- 删除指向指针的指针是运行时错误吗
- 将指针设置为"nullptr"并不能防止双重删除?
- 为什么示例代码访问IUnknown中已删除的内存
- 如何通过 getter 函数删除矢量的元素?
- 从控制台中删除最后打印的元素
- C++中的线程安全删除
- 如何从存储在std::映射中的std::集中删除元素
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数