5
int main(){     

vector<Customer*> newcustomer;

newcustomer.push_back(new Customer("III", 123333, 555));
newcustomer.push_back(new Customer("LOL", 122222, 444));
newcustomer.push_back(new Customer("PPL", 121111, 333));

for (int i = 0; i < 3; i++){
    cout << newcustomer[i]->getName() << endl;
    cout << newcustomer[i]->getPhone() << endl;
    cout << newcustomer[i]->getID() << endl;
    cout << endl;
}






system("pause");
return 0;

}

So I have made a class called customer, and you can insert new customer, getName returns the name, getPhone returns phone number and GetID returns ID, Now I want to earse everything off that vector, Not sure how to do it.

Ggbeastboi
  • 77
  • 1
  • 5

5 Answers5

6

To erase all the elements from the vector your can simply use myvector.erase (myvector.begin(),myvector.end()); or myvector.clear(). But here problem is not just erasing elements from vector but also deleting memory allocated on heap. Below is my solution.

int main(){     

vector<Customer*> newcustomer;

newcustomer.push_back(new Customer("III", 123333, 555));
newcustomer.push_back(new Customer("LOL", 122222, 444));
newcustomer.push_back(new Customer("PPL", 121111, 333));

for (int i = 0; i < 3; i++){
    cout << newcustomer[i]->getName() << endl;
    cout << newcustomer[i]->getPhone() << endl;
    cout << newcustomer[i]->getID() << endl;
    cout << endl;
}


while(!newcustomer.empty())
{
    Customer *cust = newcustomer.front();
    newcustomer.erase(newcustomer.begin());
    delete cust;
}

system("pause");
return 0;

}
HadeS
  • 2,020
  • 19
  • 36
3

If you simply want to erase everything off the vector, use: http://www.cplusplus.com/reference/vector/vector/erase/

It is the erase function for vectors

// erase the first 3 elements:
newcustomer.erase (newcustomer.begin(),newcustomer.begin()+3);
Fuad
  • 1,419
  • 1
  • 16
  • 31
  • Sorry, should it be +2? or +3, I only want to erase the 3 I have in my vector – Ggbeastboi Jun 21 '15 at 03:17
  • oo its +3, Thank You soo much – Ggbeastboi Jun 21 '15 at 03:19
  • it is +3 because the second argument is always 1 PAST the end of your vector. in the reference site, it states "... or a range of elements ([first,last))." note the square bracket and round bracket difference between first and last ^ – Fuad Jun 21 '15 at 03:19
  • 5
    That will leak the memory allocated for each object. – Nik Bougalis Jun 21 '15 at 03:22
  • hmm don't the destructors for the objects get invoked when you erase it from the vector? if they don't, then I guess you'd have to manually loop through and use 'delete' for each object – Fuad Jun 21 '15 at 03:25
  • 3
    If you *really really* want to erase everything, we have `vector::clear()`. – T.C. Jun 21 '15 at 03:31
  • 1
    If you use `new` to make an object, it lives on until manually deleted. So yeah, you'd have to delete each one before clearing. Fortunately, three things you can do. One not use a vector of pointers (vector newcustomer) and push back a temporary (`newcustomer.push_back(Customer("III", 123333, 555));`). The temp Custommer will destruct on it's own and the one in the vector will destruct when removed from the vector. Second solution requires a C++11-compliant compiler. You can replace pushing back a temporary with emplace_back, which constructs the Customer directly in the vector. – user4581301 Jun 21 '15 at 03:38
  • Continuing, `newcustomer.emplace_back("III", 123333, 555);`. The third also requires C++11. You can make a vector of smart pointers, but I don't think this is the behaviour you are looking for. If having a pointer is what you need, start reading here: http://stackoverflow.com/questions/3283778/why-can-i-not-push-back-a-unique-ptr-into-a-vector – user4581301 Jun 21 '15 at 03:48
  • 1
    Yes destructors for objects do get called. What's the destructor for a pointer? Hint: not the same as the destructor of the object it points to. – Nik Bougalis Jun 21 '15 at 03:49
  • 1
    @Ggbestboi: for what you asked, you probably want `end()`, not `begin() + N`. –  Jun 21 '15 at 06:41
1

You probably shouldn't use vector<Customer*>; for most applications vector<Customer> would be better, and for most of the remaining applications, vector<unique_ptr<Customer>> (or sometimes vector<shared_ptr<Customer>>) would be better.

But to answer your question, to do something to every element of a vector, you use a loop:

for(auto &x: newcustomer) { 
    delete x;
    // x = nullptr; // optional: don't leave a dangling pointer
}
0

At the end of your function, newcustomer will go out of scope and it's destructor will be invoked. The destructor for std::vector erases the contents of the vector, calling destructors when applicable.

You can invoke this behavior early by calling the clear member function:

#include <iostream>
#include <vector>

#include <iostream>
#include <vector>

struct S {
    S(const char* v_) : m_v(v_) {}
    ~S() {
        std::cout << "destructing ~S(" << m_v << ")\n";
    }
    const char* m_v;
};

int main()
{
    std::vector<S> v;
    v.emplace_back("hello");
    v.clear();

    v.emplace_back("fin");
}

http://ideone.com/MyKF6a

You can also remove a specific range of elements using iterators:

v.erase(v.begin(), v.end());

However: It should be noted that you are using pointers, and erasing pointers from a vector doesn't free the instances they point to:

#include <iostream>
#include <vector>

struct S {
    S(const char* v_) : m_v(v_) {}
    ~S() {
        std::cout << "destructing ~S(" << m_v << ")\n";
    }
    const char* m_v;
};

int main()
{
    std::vector<S*> v;
    v.push_back(new S("hello"));
    v.clear();

    v.push_back(new S("fin"));
}

http://ideone.com/QZLRXv - no output because nothing is freed.

Memory that you have allocated with new has to be delete or delete[]d.

You can either do this yourself:

for (Customer* ptr : newcustomer) {
    delete ptr;
}
newcustomer.clear();

Or you can use one of the standard pointer management classes.

std::vector<std::unique_ptr<Customer>> newcustomer;

newcustomer.emplace_back(std::make_unique<Customer>(...));

Full code:

#include <iostream>
#include <vector>
#include <memory>

struct Customer
{
    Customer(const char* name_, int i_, int j_)
        : m_name(name_), m_i(i_), m_j(j_) {}
    ~Customer()
    {
        std::cout << "~Customer(" << m_name << ")\n";
    }

    const char* m_name;
    int m_i, m_j;

    const char* getName() const noexcept { return m_name; }
    int getPhone() const noexcept { return m_i; }
    int getID() const noexcept { return m_j; }
};

int main()
{     
    std::vector<std::unique_ptr<Customer>> customers;

    customers.emplace_back(std::make_unique<Customer>("Andy", 123, 111));
    customers.emplace_back(std::make_unique<Customer>("Bob", 124, 222));
    customers.emplace_back(std::make_unique<Customer>("Chris", 125, 333));

    for (auto& ptr : customers) {
        std::cout << ptr->getName() << "\n";
        std::cout << ptr->getPhone() << "\n";
        std::cout << ptr->getID() << "\n";
        std::cout << "\n";
    }

    // remove the first customer
    std::cout << "pop:\n";
    customers.erase(customers.begin());

    // remove the rest
    std::cout << "clear:\n";
    customers.clear();
}

http://ideone.com/3x39LV

kfsone
  • 23,617
  • 2
  • 42
  • 74
0

As noted above newcustomer.clear() will empty the vector, but it won't take care of the pointers. HadeS takers care of that problem in his or her solution. Here are a few more ways to solve the problem.

Unlike some languages, in C++ one does not have to make a pointer with new. This approach discards the pointer and directly stores the Customer in the vector. This is generally the safest solution as you have to work at it to make this solution go wrong.

int main()
{

    vector<Customer> newcustomer;

    newcustomer.push_back(Customer("III", 123333, 555));
    newcustomer.push_back(Customer("LOL", 122222, 444));
    newcustomer.push_back(Customer("PPL", 121111, 333));

    // do stuff

    newcustomer.clear();

    return 0;

}

This is a bit clunky. You make a temporary Customer (calls constructor) and copy it into the vector (calls copy constructor). With the appropriate debugging statements int he Customer constructors and destructor you wind up with crap that looks like this:

create III
copy III
destroy III
create LOL
copy LOL
copy III
destroy III
destroy LOL
create PPL
copy PPL
copy III
copy LOL
destroy III
destroy LOL
destroy PPL
Use III
Use LOL
Use PPL
destroy III
destroy LOL
destroy PPL

3 creates, 6 copies, 9 destroys.

If Customer is composed of pointers or complex custom data types, odds are pretty good you'll need to define the copy constructor to make this work. See the Rule Of Three.

C++11 has a less cumbersome approach:

int main()
{

    vector<Customer> newcustomer;

    newcustomer.emplace_back("III", 123333, 555);
    newcustomer.emplace_back("LOL", 122222, 444);
    newcustomer.emplace_back("PPL", 121111, 333);

    // do stuff

    newcustomer.clear();

    return 0;

}

Gets rid of a bit of the work done by the first version. Output looks like this:

create III
create LOL
copy III
destroy III
create PPL
copy III
copy LOL
destroy III
destroy LOL
Use III
Use LOL
Use PPL
destroy III
destroy LOL
destroy PPL

3 creates, 3 copies, 6 destroys.

If Customer has a move constructor, the output looks like this:

create III
create LOL
move III
destroy 
create PPL
move III
move LOL
destroy 
destroy 
Use III
Use LOL
Use PPL
destroy III
destroy LOL
destroy PPL

3 creates, 3 moves, 6 destroys.

Worth the time implementing a move constructor if Customer takes a long time to copy or uses a lot of RAM you'd rather not duplicate even temporarily. Though if you're using a lot of RAM, generally the copy is going to take a long time.

Important note: See how there are a bunch of destroys that don't say who they were? That's because the move constructor literally moves the data from source to destination. Source no longer has any data. It's up to the move constructor to not leave the source in such a state that source will exhibit undefined behaviour if used after the move. And Welcome to the Rule of 5.

If for some reason you have to have pointers, wrapping the suckers in smart pointers can make your life a lot easier on the memory management front. For example:

int main()
{

    vector<unique_ptr<Customer>> newcustomer;

    newcustomer.emplace_back(new Customer("III", 123333, 555));
    newcustomer.emplace_back(new Customer("LOL", 122222, 444));
    newcustomer.emplace_back(new Customer("PPL", 121111, 333));

    // do stuff

    newcustomer.clear();

    return 0;

}

This one's output looks like the bee's knees:

create III
create LOL
create PPL
Use III
Use LOL
Use PPL
destroy III
destroy LOL
destroy PPL

But what isn't being displayed is the unique_ptrs are being created, moved, and destroyed at the same rate as Customers in the previous sample. Depending on the cost of the Customer's move constructor, you may or may not save any time or effort with the unique_ptr.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • If you are going to list all possible optimizations you should probably mention about using `reserve` first if you know how big the `vector` will be. That way you avoid all reallocations and moves. – Chris Drew Jun 21 '15 at 08:06