Deleting raw pointers from std::vector

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












17















I have following pattern:



  1. I have a std::vector containing raw pointers to objects (I know raw pointers are "evil", but it's legacy software needing to be maintained).

  2. Now for each element in the vector I need to do a test and if the test is positive do something with the pointer, delete it and then remove it from the vector:

Pseudo code:



for each pointer in vector

if (SomeTest(pointer))

DoSomething(pointer)
delete pointer
remove pointer from vector




I'm unable to come up with some nice clean code for this.



This link provides different approaches, but they all look more or less cumbersome to me.



Cumbersome solution I'm using now:



for(auto & p : v)

if (SomeTest(p))

DoSomething(p);
delete p;
p = nullptr;



v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());









share|improve this question



















  • 10





    sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

    – user463035818
    Feb 11 at 14:04






  • 1





    The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

    – Kenny Ostrom
    Feb 11 at 14:04







  • 5





    What specifically is wrong with the erase_if?

    – Useless
    Feb 11 at 14:07






  • 1





    @user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

    – Max Langhof
    Feb 11 at 14:13






  • 4





    @MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

    – user463035818
    Feb 11 at 14:15















17















I have following pattern:



  1. I have a std::vector containing raw pointers to objects (I know raw pointers are "evil", but it's legacy software needing to be maintained).

  2. Now for each element in the vector I need to do a test and if the test is positive do something with the pointer, delete it and then remove it from the vector:

Pseudo code:



for each pointer in vector

if (SomeTest(pointer))

DoSomething(pointer)
delete pointer
remove pointer from vector




I'm unable to come up with some nice clean code for this.



This link provides different approaches, but they all look more or less cumbersome to me.



Cumbersome solution I'm using now:



for(auto & p : v)

if (SomeTest(p))

DoSomething(p);
delete p;
p = nullptr;



v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());









share|improve this question



















  • 10





    sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

    – user463035818
    Feb 11 at 14:04






  • 1





    The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

    – Kenny Ostrom
    Feb 11 at 14:04







  • 5





    What specifically is wrong with the erase_if?

    – Useless
    Feb 11 at 14:07






  • 1





    @user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

    – Max Langhof
    Feb 11 at 14:13






  • 4





    @MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

    – user463035818
    Feb 11 at 14:15













17












17








17


3






I have following pattern:



  1. I have a std::vector containing raw pointers to objects (I know raw pointers are "evil", but it's legacy software needing to be maintained).

  2. Now for each element in the vector I need to do a test and if the test is positive do something with the pointer, delete it and then remove it from the vector:

Pseudo code:



for each pointer in vector

if (SomeTest(pointer))

DoSomething(pointer)
delete pointer
remove pointer from vector




I'm unable to come up with some nice clean code for this.



This link provides different approaches, but they all look more or less cumbersome to me.



Cumbersome solution I'm using now:



for(auto & p : v)

if (SomeTest(p))

DoSomething(p);
delete p;
p = nullptr;



v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());









share|improve this question
















I have following pattern:



  1. I have a std::vector containing raw pointers to objects (I know raw pointers are "evil", but it's legacy software needing to be maintained).

  2. Now for each element in the vector I need to do a test and if the test is positive do something with the pointer, delete it and then remove it from the vector:

Pseudo code:



for each pointer in vector

if (SomeTest(pointer))

DoSomething(pointer)
delete pointer
remove pointer from vector




I'm unable to come up with some nice clean code for this.



This link provides different approaches, but they all look more or less cumbersome to me.



Cumbersome solution I'm using now:



for(auto & p : v)

if (SomeTest(p))

DoSomething(p);
delete p;
p = nullptr;



v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());






c++ stdvector






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 11 at 14:15







Jabberwocky

















asked Feb 11 at 14:01









JabberwockyJabberwocky

27.8k93774




27.8k93774







  • 10





    sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

    – user463035818
    Feb 11 at 14:04






  • 1





    The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

    – Kenny Ostrom
    Feb 11 at 14:04







  • 5





    What specifically is wrong with the erase_if?

    – Useless
    Feb 11 at 14:07






  • 1





    @user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

    – Max Langhof
    Feb 11 at 14:13






  • 4





    @MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

    – user463035818
    Feb 11 at 14:15












  • 10





    sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

    – user463035818
    Feb 11 at 14:04






  • 1





    The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

    – Kenny Ostrom
    Feb 11 at 14:04







  • 5





    What specifically is wrong with the erase_if?

    – Useless
    Feb 11 at 14:07






  • 1





    @user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

    – Max Langhof
    Feb 11 at 14:13






  • 4





    @MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

    – user463035818
    Feb 11 at 14:15







10




10





sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

– user463035818
Feb 11 at 14:04





sorry, nitpick: raw pointers to objects owned by someone else are rather harmless. Only owning raw pointers are evil

– user463035818
Feb 11 at 14:04




1




1





The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

– Kenny Ostrom
Feb 11 at 14:04






The only concern I can think of is invalidating the iterator, and messing up your loop, which wouldn't have anything to do with the pointer. Perhaps you could post a Minimal, Complete, and Verifiable example. (consider std::remove_if ?)

– Kenny Ostrom
Feb 11 at 14:04





5




5





What specifically is wrong with the erase_if?

– Useless
Feb 11 at 14:07





What specifically is wrong with the erase_if?

– Useless
Feb 11 at 14:07




1




1





@user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

– Max Langhof
Feb 11 at 14:13





@user463035818 Needless to say, deleteing raw pointers only makes sense specifically in the evil case of owning raw pointers. The statement in the question does not explicitly attribute ownership to the pointers so you're technically correct to nitpick.

– Max Langhof
Feb 11 at 14:13




4




4





@MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

– user463035818
Feb 11 at 14:15





@MaxLanghof if the vector is responsible to delete them then I would say the vector owns them. Anyhow, I was specifically refering to "I know raw pointers are "evil"" and I am a bit picky whem something gets the "evil" attribute. Too easily this can lead to misunderstanding

– user463035818
Feb 11 at 14:15












7 Answers
7






active

oldest

votes


















28














As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)



std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.



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));



Full program



#include <iostream>
#include <algorithm>
#include <vector>

int main()

std::vector v = new int0, new int1, new int2 ;

// 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));



Live demo



To go further



This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function (2).



  • (1) is solved by std::stable_partition.

  • (2) is not that hard:

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));



Usage:



delete_if(v, SomeTest, DoSomething);


Live demo






share|improve this answer

























  • Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

    – user202729
    Feb 11 at 16:13











  • I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

    – YSC
    Feb 11 at 16:24



















13














You can use std::remove_if I am not sure why the article you linked uses std::remove_if before deleting the pointers because that won't work. You have to delete the pointers before the removal:



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));


Notes: Why this is safe.



Deleting the pointer does not modify the pointer itself, but the object being pointed to. That means that no elements are modified with this approach.



The standard at C++17 28.6.8 5 guarantees that the predicate will be called just once for each element.






share|improve this answer

























  • Responding to your comment, yes: that's a good idea for this specific case. (+1)

    – YSC
    Feb 11 at 14:53


















6














The simplest solution - starting from the linked article - is to take the erase_if function



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));



and just call it with



erase_if(v, (T *pointer)

if (SomeTest(pointer))

DoSomething(pointer);
delete pointer;
return true; //remove pointer from vector

return false;
);


You can obviously split your predicate in two if you want to separate the SomeTest/DoSomething part from the delete part:



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));



Since you haven't said why you don't like the erase_if you linked yourself, I can't guess whether this has the same problem.






share|improve this answer




















  • 1





    There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

    – You
    Feb 11 at 15:37











  • @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

    – Arne Vogel
    Feb 11 at 15:44











  • Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

    – You
    Feb 11 at 15:49











  • @ArneVogel The standard guarantees the predicate will only be called once per element

    – Galik
    Feb 11 at 17:12











  • I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

    – Arne Vogel
    Feb 11 at 20:44


















2














With the following approach first you split the elements to be deleted, then you delete, then you adjust the vector.



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));


The predicate provided must be true for element to keep in order to work, as elements failing the predicate are in the last range.






share|improve this answer
































    0














    Assumed you have a vector of int pointer. Here is my solution:



    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++;







    share|improve this answer




















    • 3





      not sure but as I understood the question this is the code that OP would like to avoid writing.

      – user463035818
      Feb 11 at 14:10











    • @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

      – Samer Tufail
      Feb 11 at 14:15






    • 3





      Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

      – NathanOliver
      Feb 11 at 14:16






    • 1





      This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

      – rustyx
      Feb 11 at 14:19







    • 4





      Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

      – rustyx
      Feb 11 at 14:27


















    0














    Some approach that I would use:



    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());





    share|improve this answer


















    • 4





      this solution is using nullptr as a magic value.

      – UmNyobe
      Feb 11 at 14:17











    • That's more or less what I'm doing now

      – Jabberwocky
      Feb 11 at 14:39







    • 1





      @UmNyobe What is wrong with using nullptr as a magic value?

      – Galik
      Feb 11 at 14:43






    • 4





      @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

      – user463035818
      Feb 11 at 14:44


















    0














    Keep it simple. YAGNI. No reason to solve a more generic and complicated version of the problem in the off chance you will need it (hint: you won't), or hunt for obscure STL methods (well, unless you wish to).



    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);





    share|improve this answer























    • <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

      – YSC
      Feb 12 at 7:14











    • Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

      – jick
      Feb 12 at 18:19











    • "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

      – YSC
      Feb 12 at 18:25












    • ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

      – jick
      Feb 12 at 18:33











    • There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

      – jick
      Feb 12 at 18:33










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54632242%2fdeleting-raw-pointers-from-stdvector%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    7 Answers
    7






    active

    oldest

    votes








    7 Answers
    7






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    28














    As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)



    std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.



    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));



    Full program



    #include <iostream>
    #include <algorithm>
    #include <vector>

    int main()

    std::vector v = new int0, new int1, new int2 ;

    // 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));



    Live demo



    To go further



    This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function (2).



    • (1) is solved by std::stable_partition.

    • (2) is not that hard:

    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));



    Usage:



    delete_if(v, SomeTest, DoSomething);


    Live demo






    share|improve this answer

























    • Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

      – user202729
      Feb 11 at 16:13











    • I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

      – YSC
      Feb 11 at 16:24
















    28














    As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)



    std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.



    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));



    Full program



    #include <iostream>
    #include <algorithm>
    #include <vector>

    int main()

    std::vector v = new int0, new int1, new int2 ;

    // 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));



    Live demo



    To go further



    This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function (2).



    • (1) is solved by std::stable_partition.

    • (2) is not that hard:

    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));



    Usage:



    delete_if(v, SomeTest, DoSomething);


    Live demo






    share|improve this answer

























    • Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

      – user202729
      Feb 11 at 16:13











    • I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

      – YSC
      Feb 11 at 16:24














    28












    28








    28







    As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)



    std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.



    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));



    Full program



    #include <iostream>
    #include <algorithm>
    #include <vector>

    int main()

    std::vector v = new int0, new int1, new int2 ;

    // 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));



    Live demo



    To go further



    This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function (2).



    • (1) is solved by std::stable_partition.

    • (2) is not that hard:

    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));



    Usage:



    delete_if(v, SomeTest, DoSomething);


    Live demo






    share|improve this answer















    As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)



    std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.



    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));



    Full program



    #include <iostream>
    #include <algorithm>
    #include <vector>

    int main()

    std::vector v = new int0, new int1, new int2 ;

    // 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));



    Live demo



    To go further



    This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function (2).



    • (1) is solved by std::stable_partition.

    • (2) is not that hard:

    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));



    Usage:



    delete_if(v, SomeTest, DoSomething);


    Live demo







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 14 at 7:24

























    answered Feb 11 at 14:06









    YSCYSC

    24.5k555111




    24.5k555111












    • Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

      – user202729
      Feb 11 at 16:13











    • I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

      – YSC
      Feb 11 at 16:24


















    • Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

      – user202729
      Feb 11 at 16:13











    • I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

      – YSC
      Feb 11 at 16:24

















    Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

    – user202729
    Feb 11 at 16:13





    Also, delete p should be handled by the UnaryDeleter, otherwise it can only be used for dynamic pointers.

    – user202729
    Feb 11 at 16:13













    I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

    – YSC
    Feb 11 at 16:24






    I disagree on that point; my reasoning is that we're solving OP's specific problem: "for each element in the vector I need to do a test and if the test is positive do something with the [raw] pointer, delete it and then remove it from the vector". There's no reason for them to not put the delete statement on the delete_if function.

    – YSC
    Feb 11 at 16:24














    13














    You can use std::remove_if I am not sure why the article you linked uses std::remove_if before deleting the pointers because that won't work. You have to delete the pointers before the removal:



    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));


    Notes: Why this is safe.



    Deleting the pointer does not modify the pointer itself, but the object being pointed to. That means that no elements are modified with this approach.



    The standard at C++17 28.6.8 5 guarantees that the predicate will be called just once for each element.






    share|improve this answer

























    • Responding to your comment, yes: that's a good idea for this specific case. (+1)

      – YSC
      Feb 11 at 14:53















    13














    You can use std::remove_if I am not sure why the article you linked uses std::remove_if before deleting the pointers because that won't work. You have to delete the pointers before the removal:



    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));


    Notes: Why this is safe.



    Deleting the pointer does not modify the pointer itself, but the object being pointed to. That means that no elements are modified with this approach.



    The standard at C++17 28.6.8 5 guarantees that the predicate will be called just once for each element.






    share|improve this answer

























    • Responding to your comment, yes: that's a good idea for this specific case. (+1)

      – YSC
      Feb 11 at 14:53













    13












    13








    13







    You can use std::remove_if I am not sure why the article you linked uses std::remove_if before deleting the pointers because that won't work. You have to delete the pointers before the removal:



    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));


    Notes: Why this is safe.



    Deleting the pointer does not modify the pointer itself, but the object being pointed to. That means that no elements are modified with this approach.



    The standard at C++17 28.6.8 5 guarantees that the predicate will be called just once for each element.






    share|improve this answer















    You can use std::remove_if I am not sure why the article you linked uses std::remove_if before deleting the pointers because that won't work. You have to delete the pointers before the removal:



    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));


    Notes: Why this is safe.



    Deleting the pointer does not modify the pointer itself, but the object being pointed to. That means that no elements are modified with this approach.



    The standard at C++17 28.6.8 5 guarantees that the predicate will be called just once for each element.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 11 at 17:22

























    answered Feb 11 at 14:21









    GalikGalik

    34.6k35281




    34.6k35281












    • Responding to your comment, yes: that's a good idea for this specific case. (+1)

      – YSC
      Feb 11 at 14:53

















    • Responding to your comment, yes: that's a good idea for this specific case. (+1)

      – YSC
      Feb 11 at 14:53
















    Responding to your comment, yes: that's a good idea for this specific case. (+1)

    – YSC
    Feb 11 at 14:53





    Responding to your comment, yes: that's a good idea for this specific case. (+1)

    – YSC
    Feb 11 at 14:53











    6














    The simplest solution - starting from the linked article - is to take the erase_if function



    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));



    and just call it with



    erase_if(v, (T *pointer)

    if (SomeTest(pointer))

    DoSomething(pointer);
    delete pointer;
    return true; //remove pointer from vector

    return false;
    );


    You can obviously split your predicate in two if you want to separate the SomeTest/DoSomething part from the delete part:



    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));



    Since you haven't said why you don't like the erase_if you linked yourself, I can't guess whether this has the same problem.






    share|improve this answer




















    • 1





      There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

      – You
      Feb 11 at 15:37











    • @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

      – Arne Vogel
      Feb 11 at 15:44











    • Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

      – You
      Feb 11 at 15:49











    • @ArneVogel The standard guarantees the predicate will only be called once per element

      – Galik
      Feb 11 at 17:12











    • I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

      – Arne Vogel
      Feb 11 at 20:44















    6














    The simplest solution - starting from the linked article - is to take the erase_if function



    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));



    and just call it with



    erase_if(v, (T *pointer)

    if (SomeTest(pointer))

    DoSomething(pointer);
    delete pointer;
    return true; //remove pointer from vector

    return false;
    );


    You can obviously split your predicate in two if you want to separate the SomeTest/DoSomething part from the delete part:



    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));



    Since you haven't said why you don't like the erase_if you linked yourself, I can't guess whether this has the same problem.






    share|improve this answer




















    • 1





      There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

      – You
      Feb 11 at 15:37











    • @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

      – Arne Vogel
      Feb 11 at 15:44











    • Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

      – You
      Feb 11 at 15:49











    • @ArneVogel The standard guarantees the predicate will only be called once per element

      – Galik
      Feb 11 at 17:12











    • I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

      – Arne Vogel
      Feb 11 at 20:44













    6












    6








    6







    The simplest solution - starting from the linked article - is to take the erase_if function



    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));



    and just call it with



    erase_if(v, (T *pointer)

    if (SomeTest(pointer))

    DoSomething(pointer);
    delete pointer;
    return true; //remove pointer from vector

    return false;
    );


    You can obviously split your predicate in two if you want to separate the SomeTest/DoSomething part from the delete part:



    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));



    Since you haven't said why you don't like the erase_if you linked yourself, I can't guess whether this has the same problem.






    share|improve this answer















    The simplest solution - starting from the linked article - is to take the erase_if function



    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));



    and just call it with



    erase_if(v, (T *pointer)

    if (SomeTest(pointer))

    DoSomething(pointer);
    delete pointer;
    return true; //remove pointer from vector

    return false;
    );


    You can obviously split your predicate in two if you want to separate the SomeTest/DoSomething part from the delete part:



    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));



    Since you haven't said why you don't like the erase_if you linked yourself, I can't guess whether this has the same problem.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 11 at 15:45









    Arne Vogel

    4,81521326




    4,81521326










    answered Feb 11 at 14:17









    UselessUseless

    44.2k55495




    44.2k55495







    • 1





      There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

      – You
      Feb 11 at 15:37











    • @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

      – Arne Vogel
      Feb 11 at 15:44











    • Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

      – You
      Feb 11 at 15:49











    • @ArneVogel The standard guarantees the predicate will only be called once per element

      – Galik
      Feb 11 at 17:12











    • I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

      – Arne Vogel
      Feb 11 at 20:44












    • 1





      There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

      – You
      Feb 11 at 15:37











    • @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

      – Arne Vogel
      Feb 11 at 15:44











    • Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

      – You
      Feb 11 at 15:49











    • @ArneVogel The standard guarantees the predicate will only be called once per element

      – Galik
      Feb 11 at 17:12











    • I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

      – Arne Vogel
      Feb 11 at 20:44







    1




    1





    There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

    – You
    Feb 11 at 15:37





    There's an issue with this approach: std::erase_if(...) is equivalent to v.erase(std::remove_if(...)), which explicitly specifies that the predicate must not modify the element.

    – You
    Feb 11 at 15:37













    @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

    – Arne Vogel
    Feb 11 at 15:44





    @You Technically it doesn't modify the element, but I guess the spirit is that p should be idempotent (callable many times without harm), and this is certainly not so in this case as the next call on the deleted pointer will probably have UB.

    – Arne Vogel
    Feb 11 at 15:44













    Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

    – You
    Feb 11 at 15:49





    Fair point. (I believe the exact wording is "The [predicate] shall not apply any non-constant function through the dereferenced iterator.", which deleteing technically doesn't do I guess since it's fine to delete a const pointer.)

    – You
    Feb 11 at 15:49













    @ArneVogel The standard guarantees the predicate will only be called once per element

    – Galik
    Feb 11 at 17:12





    @ArneVogel The standard guarantees the predicate will only be called once per element

    – Galik
    Feb 11 at 17:12













    I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

    – Arne Vogel
    Feb 11 at 20:44





    I assume you are deducing this from (alg.remove/5) – IMO it's still a bit of a technicality. If I was doing a code review, I'd suggest switching to partition/stable_partition or writing a meaningful comment for why it is correct.

    – Arne Vogel
    Feb 11 at 20:44











    2














    With the following approach first you split the elements to be deleted, then you delete, then you adjust the vector.



    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));


    The predicate provided must be true for element to keep in order to work, as elements failing the predicate are in the last range.






    share|improve this answer





























      2














      With the following approach first you split the elements to be deleted, then you delete, then you adjust the vector.



      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));


      The predicate provided must be true for element to keep in order to work, as elements failing the predicate are in the last range.






      share|improve this answer



























        2












        2








        2







        With the following approach first you split the elements to be deleted, then you delete, then you adjust the vector.



        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));


        The predicate provided must be true for element to keep in order to work, as elements failing the predicate are in the last range.






        share|improve this answer















        With the following approach first you split the elements to be deleted, then you delete, then you adjust the vector.



        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));


        The predicate provided must be true for element to keep in order to work, as elements failing the predicate are in the last range.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Feb 11 at 14:34

























        answered Feb 11 at 14:27









        UmNyobeUmNyobe

        17.8k73875




        17.8k73875





















            0














            Assumed you have a vector of int pointer. Here is my solution:



            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++;







            share|improve this answer




















            • 3





              not sure but as I understood the question this is the code that OP would like to avoid writing.

              – user463035818
              Feb 11 at 14:10











            • @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

              – Samer Tufail
              Feb 11 at 14:15






            • 3





              Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

              – NathanOliver
              Feb 11 at 14:16






            • 1





              This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

              – rustyx
              Feb 11 at 14:19







            • 4





              Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

              – rustyx
              Feb 11 at 14:27















            0














            Assumed you have a vector of int pointer. Here is my solution:



            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++;







            share|improve this answer




















            • 3





              not sure but as I understood the question this is the code that OP would like to avoid writing.

              – user463035818
              Feb 11 at 14:10











            • @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

              – Samer Tufail
              Feb 11 at 14:15






            • 3





              Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

              – NathanOliver
              Feb 11 at 14:16






            • 1





              This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

              – rustyx
              Feb 11 at 14:19







            • 4





              Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

              – rustyx
              Feb 11 at 14:27













            0












            0








            0







            Assumed you have a vector of int pointer. Here is my solution:



            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++;







            share|improve this answer















            Assumed you have a vector of int pointer. Here is my solution:



            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++;








            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 11 at 14:09

























            answered Feb 11 at 14:07









            Loc TranLoc Tran

            1,142714




            1,142714







            • 3





              not sure but as I understood the question this is the code that OP would like to avoid writing.

              – user463035818
              Feb 11 at 14:10











            • @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

              – Samer Tufail
              Feb 11 at 14:15






            • 3





              Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

              – NathanOliver
              Feb 11 at 14:16






            • 1





              This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

              – rustyx
              Feb 11 at 14:19







            • 4





              Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

              – rustyx
              Feb 11 at 14:27












            • 3





              not sure but as I understood the question this is the code that OP would like to avoid writing.

              – user463035818
              Feb 11 at 14:10











            • @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

              – Samer Tufail
              Feb 11 at 14:15






            • 3





              Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

              – NathanOliver
              Feb 11 at 14:16






            • 1





              This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

              – rustyx
              Feb 11 at 14:19







            • 4





              Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

              – rustyx
              Feb 11 at 14:27







            3




            3





            not sure but as I understood the question this is the code that OP would like to avoid writing.

            – user463035818
            Feb 11 at 14:10





            not sure but as I understood the question this is the code that OP would like to avoid writing.

            – user463035818
            Feb 11 at 14:10













            @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

            – Samer Tufail
            Feb 11 at 14:15





            @LocTran I usually do it = vector.erase(it) .. not so nice as your old, new :)

            – Samer Tufail
            Feb 11 at 14:15




            3




            3





            Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

            – NathanOliver
            Feb 11 at 14:16





            Why use old? DoSomething(*it) delete *it; it = vpi.erase(it); does the same thing.

            – NathanOliver
            Feb 11 at 14:16




            1




            1





            This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

            – rustyx
            Feb 11 at 14:19






            This solution is O(N^2) (think about the elements which need to be moved when you erase in the middle). Use std::partition followed by a single erase instead.

            – rustyx
            Feb 11 at 14:19





            4




            4





            Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

            – rustyx
            Feb 11 at 14:27





            Consider a vector with 1000 elements, of which first 100 need to be removed. How many times an element that remains would need to be moved inside the vector (around 95000).

            – rustyx
            Feb 11 at 14:27











            0














            Some approach that I would use:



            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());





            share|improve this answer


















            • 4





              this solution is using nullptr as a magic value.

              – UmNyobe
              Feb 11 at 14:17











            • That's more or less what I'm doing now

              – Jabberwocky
              Feb 11 at 14:39







            • 1





              @UmNyobe What is wrong with using nullptr as a magic value?

              – Galik
              Feb 11 at 14:43






            • 4





              @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

              – user463035818
              Feb 11 at 14:44















            0














            Some approach that I would use:



            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());





            share|improve this answer


















            • 4





              this solution is using nullptr as a magic value.

              – UmNyobe
              Feb 11 at 14:17











            • That's more or less what I'm doing now

              – Jabberwocky
              Feb 11 at 14:39







            • 1





              @UmNyobe What is wrong with using nullptr as a magic value?

              – Galik
              Feb 11 at 14:43






            • 4





              @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

              – user463035818
              Feb 11 at 14:44













            0












            0








            0







            Some approach that I would use:



            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());





            share|improve this answer













            Some approach that I would use:



            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());






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Feb 11 at 14:11









            S.M.S.M.

            6,18641628




            6,18641628







            • 4





              this solution is using nullptr as a magic value.

              – UmNyobe
              Feb 11 at 14:17











            • That's more or less what I'm doing now

              – Jabberwocky
              Feb 11 at 14:39







            • 1





              @UmNyobe What is wrong with using nullptr as a magic value?

              – Galik
              Feb 11 at 14:43






            • 4





              @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

              – user463035818
              Feb 11 at 14:44












            • 4





              this solution is using nullptr as a magic value.

              – UmNyobe
              Feb 11 at 14:17











            • That's more or less what I'm doing now

              – Jabberwocky
              Feb 11 at 14:39







            • 1





              @UmNyobe What is wrong with using nullptr as a magic value?

              – Galik
              Feb 11 at 14:43






            • 4





              @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

              – user463035818
              Feb 11 at 14:44







            4




            4





            this solution is using nullptr as a magic value.

            – UmNyobe
            Feb 11 at 14:17





            this solution is using nullptr as a magic value.

            – UmNyobe
            Feb 11 at 14:17













            That's more or less what I'm doing now

            – Jabberwocky
            Feb 11 at 14:39






            That's more or less what I'm doing now

            – Jabberwocky
            Feb 11 at 14:39





            1




            1





            @UmNyobe What is wrong with using nullptr as a magic value?

            – Galik
            Feb 11 at 14:43





            @UmNyobe What is wrong with using nullptr as a magic value?

            – Galik
            Feb 11 at 14:43




            4




            4





            @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

            – user463035818
            Feb 11 at 14:44





            @Galik maybe the vector does contain nullptr and maybe SomeTest returns false for a nullptr

            – user463035818
            Feb 11 at 14:44











            0














            Keep it simple. YAGNI. No reason to solve a more generic and complicated version of the problem in the off chance you will need it (hint: you won't), or hunt for obscure STL methods (well, unless you wish to).



            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);





            share|improve this answer























            • <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

              – YSC
              Feb 12 at 7:14











            • Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

              – jick
              Feb 12 at 18:19











            • "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

              – YSC
              Feb 12 at 18:25












            • ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

              – jick
              Feb 12 at 18:33











            • There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

              – jick
              Feb 12 at 18:33















            0














            Keep it simple. YAGNI. No reason to solve a more generic and complicated version of the problem in the off chance you will need it (hint: you won't), or hunt for obscure STL methods (well, unless you wish to).



            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);





            share|improve this answer























            • <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

              – YSC
              Feb 12 at 7:14











            • Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

              – jick
              Feb 12 at 18:19











            • "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

              – YSC
              Feb 12 at 18:25












            • ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

              – jick
              Feb 12 at 18:33











            • There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

              – jick
              Feb 12 at 18:33













            0












            0








            0







            Keep it simple. YAGNI. No reason to solve a more generic and complicated version of the problem in the off chance you will need it (hint: you won't), or hunt for obscure STL methods (well, unless you wish to).



            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);





            share|improve this answer













            Keep it simple. YAGNI. No reason to solve a more generic and complicated version of the problem in the off chance you will need it (hint: you won't), or hunt for obscure STL methods (well, unless you wish to).



            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);






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Feb 11 at 18:33









            jickjick

            28719




            28719












            • <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

              – YSC
              Feb 12 at 7:14











            • Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

              – jick
              Feb 12 at 18:19











            • "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

              – YSC
              Feb 12 at 18:25












            • ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

              – jick
              Feb 12 at 18:33











            • There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

              – jick
              Feb 12 at 18:33

















            • <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

              – YSC
              Feb 12 at 7:14











            • Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

              – jick
              Feb 12 at 18:19











            • "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

              – YSC
              Feb 12 at 18:25












            • ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

              – jick
              Feb 12 at 18:33











            • There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

              – jick
              Feb 12 at 18:33
















            <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

            – YSC
            Feb 12 at 7:14





            <algorithm> is not a bunch of "obscure STL methods". Learn them, use them. They produce easy to read, easy to maintain, easy to optimise code.

            – YSC
            Feb 12 at 7:14













            Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

            – jick
            Feb 12 at 18:19





            Of course, "easy" is in the eye of the beholder, but I've seen too many code with multiple levels of templatized inheritance which could have been written in a simple for loop or switch statement, only if the programmer resisted the urge to generalize everything to the maximum. If anyone finds std::for_each with lambdas easier than for, then it's their taste: but I doubt it will be faster.

            – jick
            Feb 12 at 18:19













            "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

            – YSC
            Feb 12 at 18:25






            "Of course, "easy" is in the eye of the beholder" No it is generally not. If an idiom exist in the C++ community, anything other than that idiom is not easy to read and increments the wtf/line of your codebase. About optimization, nothing can be said without testing, but generally idiomatic code and code relying on the standard library are better understood by the compiler and optimized in a better way.

            – YSC
            Feb 12 at 18:25














            ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

            – jick
            Feb 12 at 18:33





            ...Easy is not in the eye of the beholder? I'm glad you agree that for loop is objectively superior! :P Jokes aside, a for loop has been the idiom of C++ since it was called "C with classes", and unlike C-style strings, it's not going anywhere. Stroustrup himself warned against "trying to write C++ as if it's $(other languages)" in his "The C++ Programming Language" (2nd Ed): I'm not sure if he changed stances later, but C++ is not exactly a functional language, and trying to write C++ as if it's one can easily end up in an overcomplicated mess.

            – jick
            Feb 12 at 18:33













            There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

            – jick
            Feb 12 at 18:33





            There's probably no harm in changing a single for loop to for_each, but it's silly to claim the latter is objectively superior just because it's new. C++ has no shortage of features that scream "Just because you can use it here doesn't necessarily mean it's a good idea to."

            – jick
            Feb 12 at 18:33

















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54632242%2fdeleting-raw-pointers-from-stdvector%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown






            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Bahrain

            Postfix configuration issue with fips on centos 7; mailgun relay