此代码有什么问题?我试图从用户定义的容器中删除重复的元素。
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] ???),令我惊讶的项目。我不明白这种奇怪的行为......
答案 0 :(得分:2)
我敢打赌,不仅一些值出现不止一次,一些单个对象在序列中出现不止一次。
当你delete
所有重复的值时,你会破坏序列中剩余的一些对象。
第二种排序(这是不必要的,因为unique
不重新排列事物,因为它删除了重复项)访问每个对象,所以它立即踩到那些只是delete
d。
一种可能的解决方案是sort
由unique
产生的两个范围内的指针set_difference( i_new_end, it_end, i_begin, i_new_end, i_sequence_inserter )
。使用set_difference
查找实际需要释放的对象 - 假设它们还没有被其他地方使用。
或者,只使用智能指针,或者根本不使用指针:v)。
请参阅我的评论 - 最佳解决方案可能完全消除指针的使用。
无论如何,这是一个示例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 );
);
解决方案,这个解决方案使用自定义迭代器而不是序列插入器。
{{1}}
答案 1 :(得分:0)
听起来在std::sort
的最后一次调用中使用的迭代器可能无效。可能是it_begin
。您可以尝试使用this->items.begin()
吗?
答案 2 :(得分:0)
在我看来,传递的迭代器实际上并非来自this->items
,而是来自其他容器。
另一种可能性是delete *i_item
导致问题,并且它只在最后一行显示为延迟反应。
编辑:另一种比你预期更频繁出现的选择是你的sort
谓词不服从严格的弱序。你可以为它显示代码吗?
答案 3 :(得分:0)
经过一些测试后,我认为i_new_end
调用无效.erase()
。
根据documentation,应该仍然有效 - 只有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提到的记忆问题。