我继承了一个接口,并实现了一个虚拟函数,该函数应该在动态分配的对象列表上做一些工作。第一步是根据一些自定义等效标准从列表中删除重复项:
class Foo { /* ... */ };
struct FooLess
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
struct FooEqual
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
void doStuff(std::list<Foo*> &foos)
{
// use the sort + unique idiom to find and erase duplicates
FooLess less;
FooEqual equal;
foos.sort( foos.begin(), foos.end(), less );
foos.erase(
std::unique( foos.begin(), foos.end(), equal ),
foos.end() ); // memory leak!
}
问题是使用sort
+ unique
并不清理内存,erase
d之后的元素在unique
之后有未指定的值,所以我不能在erase
之前自己进行清理。我在考虑这样的事情:
void doStuff(std::list<Foo*> &foos)
{
// make a temporary copy of the input as a list of auto_ptr's
std::list<auto_ptr<Foo>> auto_foos;
for (std::list<Foo>::iterator it = foos.begin(); it != foos.end(); ++it)
auto_foos.push_back(auto_ptr<Foo>(*it));
foos.clear();
FooLess less; // would need to change implementation to work on auto_ptr<Foo>
FooEqual equal; // likewise
auto_foos.sort( auto_foos.begin(), auto_foos.end(), less );
auto_foos.erase(
std::unique( auto_foos.begin(), auto_foos.end(), equal ),
auto_foos.end() ); // okay now, duplicates deallocated
// transfer ownership of the remaining objects back
for (std::list<auto_ptr<Foo>>::iterator it = auto_foos.begin();
it != auto_foos.end(); ++it)
{ foos.push_back(it->get()); it->release(); }
}
这可以,或者我错过了什么?
我无法使用C ++ 11(可能是Boost)或更改函数签名以接受简单Foo
的列表。
答案 0 :(得分:2)
要将对象放入标准容器中,对象需要值语义(标准说&#34;复制可分配&#34;和&#34;复制可构造&#34;)。除此之外,这意味着复制构造函数和赋值运算符需要创建对象的副本(保留原始对象)
auto_ptr复制构造函数不会这样做。相反,复制构造函数和赋值运算符转移指针的所有权。
因此,标准容器不可能包含auto_ptr。
许多实现(如在编译器和标准库中)都有标准容器和/或auto_ptr编码,因此尝试使用auto_ptr容器将触发编译器错误。不幸的是,并非所有实现都这样做。
答案 1 :(得分:1)
您可以在C ++ 98中使用以下方法:
std::auto_ptr
无法执行的操作。有一个旧版本的东西,其中包含一个标记所有权的bool
类型的附加字段。它被标记为可变,因此它也可以在复制时从被读取的对象中进行修改。仅当owned
为真时,才删除对象。类似的东西:==
template <class T> class owning_ptr
{
T* ptr;
mutable bool owns;
public:
void operator =(T* src) { ptr = src; owns = true; }
owning_ptr(const owning_ptr& other)
{
// copy the pointer, but STEAL ownership!
ptr = other.ptr; owns = other.owns; other.owns = false;
}
T* release() { owns = false; return ptr; }
~owning_ptr() { if ( owns ) delete ptr; }
/* ... some lacking stuff ..*/
};
您可以尝试boost::shared_ptr
您可以尝试在循环中尝试std::unique
,而不是std::adjacent_find
。然后,您将找到与equal
“相同”的所有元素。如果有多个元素,你将把它们擦除(你可以这样做,因为它是一个列表,所以迭代器仍然有效)。