[英]How to convert a std::vector of unique pointers to a std::span of raw pointers?
[英]Deleting raw pointers from std::vector
我有以下模式:
std::vector
其中包含指向對象的原始指針(我知道原始指針是“邪惡的”,但是它需要保留舊版軟件)。 偽代碼:
for each pointer in vector
{
if (SomeTest(pointer))
{
DoSomething(pointer)
delete pointer
remove pointer from vector
}
}
我無法為此提供一些很好的干凈代碼。
該鏈接提供了不同的方法,但是它們對我來說都顯得比較麻煩。
我現在使用的笨拙的解決方案:
for(auto & p : v)
{
if (SomeTest(p))
{
DoSomething(p);
delete p;
p = nullptr;
}
}
v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
通常,答案是:知道您的<algorithm>
s(並且對我自己有一個很好的提醒);)
std::partition
是你在找什么: std::partition(begin, end, p)
“動作”的范圍內的元素begin
, end
它不滿足謂詞) p
的范圍的結束; 然后可以將它們視為批處理。
auto const to_be_removed = std::partition(begin(v), end(v), [](auto p){ /* predicate */ });
std::for_each(to_be_removed, end(v), [](auto p) {
/* crunch */
delete p;
});
v.erase(to_be_removed, end(v));
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector v = { new int{0}, new int{1}, new int{2} };
// let's delete all even values
auto const to_be_removed = std::partition(begin(v), end(v), [](auto p){ return *p % 2 != 0; });
std::for_each(to_be_removed, end(v), [](auto p) {
std::cout << "Deleting value " << *p << "...\n";
delete p;
});
v.erase(to_be_removed, end(v));
}
此實現有兩個主要缺點:向量的順序不穩定(1),它可能會分解為可重用函數(2)。
std::stable_partition
解決。 template<class InputIt, class UnaryPredicate, class UnaryDeleter>
InputIt delete_if(InputIt begin, InputIt end, UnaryPredicate p, UnaryDeleter d)
{
auto const to_be_removed = std::stable_partition(begin, end, std::not_fn(p));
std::for_each(to_be_removed, end, [d](auto p) { d(p) ; delete p; });
return to_be_removed;
}
template<class Container, class UnaryPredicate, class UnaryDeleter>
auto delete_if(Container& c, UnaryPredicate p, UnaryDeleter d)
{
using std::begin, std::end;
return c.erase(delete_if(begin(c), end(c), p, d), end(c));
}
用法 :
delete_if(v, SomeTest, DoSomething);
您可以使用std::remove_if
我不確定您鏈接的文章為何在刪除指針之前使用std::remove_if
,因為這行不通。 您必須在刪除 之前 刪除指針:
std::vector<int*> v;
v.erase(std::remove_if(std::begin(v), std::end(v), [](int* p){
// do your test and do not remove on failure
if(!SomeTest(p))
return false; // keep this one
DoSomething(p);
// Now we remove but be sure to delete here, before the
// element is moved (and therefore invalidated)
delete p;
return true; // signal for removal
}), std::end(v));
注意:為什么這樣比較安全。
刪除指針不會修改指針本身,而是指向的對象。 這意味着該方法不會修改任何元素。
C++17 28.6.8 5
的標准保證謂詞對於每個元素僅被調用一次。
最簡單的解決方案-從鏈接的文章開始-是采用了erase_if
函數
template <typename Container, typename Pred>
void erase_if(Container &c, Pred p)
{
c.erase(std::remove_if(std::begin(c), std::end(c), p), std::end(c));
}
然后用
erase_if(v, [](T *pointer)
{
if (SomeTest(pointer))
{
DoSomething(pointer);
delete pointer;
return true; //remove pointer from vector
}
return false;
});
如果要將SomeTest / DoSomething部分與delete
部分分開,顯然可以將謂詞一分為二:
template <typename Container, typename Pred>
void delete_if(Container &c, Pred p)
{
auto e = std::remove_if(std::begin(c), std::end(c),
[&p](Container::value_type *pointer)
{
if (p(pointer)) {
delete pointer;
return true;
}
return false;
});
c.erase(e, std::end(c));
}
既然您沒有說過為什么不喜歡erase_if
如果您自己鏈接了,那么我無法猜測這是否有相同的問題。
使用以下方法,首先拆分要刪除的元素,然后刪除,然后調整向量。
auto badIt = std::stable_partition(std::beging(v), std::end(v), SomeTestInverse);
std::for_each(badIt, std::end(v), [](auto e){ DoSomething(e); delete e;});
v.erase(badIt,std::end(v));
提供的謂詞必須為true才能使元素保留才能正常工作,因為未通過謂詞的元素位於最后一個范圍內。
假設您有一個向量int指針。 這是我的解決方案:
vector<int*> vpi;
for (vector<int*>::iterator it = vpi.begin(); it != vpi.end(); )
{
if (SomeTest(*it))
{
DoSomething(*it)
int* old = *it;
it = vpi.erase(it);
delete old;
} else
{
it++;
}
}
我將使用的一些方法:
for (auto i = vector.begin(); i != vector.end(); ++i) {
if (SomeTest(*i)) {
DoSomething(*i);
delete *i;
*i = nullptr;
}
}
vector.erase(std::remove(vector.begin(), vector.end(), nullptr), vector.end());
把事情簡單化。 亞尼 沒有理由在可能的情況下解決這個問題的更通用和更復雜的版本(提示:您不需要),或尋找晦澀的STL方法(當然,除非您願意 )。
size_t target = 0;
for (size_t idx = 0; idx < v.size(); idx++) {
if (should_delete(v[idx]))
delete v[idx];
else
v[target++] = v[idx];
}
v.resize(target);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.