Why operator delete in for_each does not work?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <algorithm>
#include <iostream>
#include <functional>
#include <vector>

struct A
{
    ~A() { std::cout << 'A'; }
};

int main()
{
    std::vector<A*> v(4, static_cast<A*>(0));
    v[0] = new A;
    v[1] = new A;
    v[2] = new A;
    v[3] = new A;
    std::for_each(v.begin(), v.end(), std::ptr_fun(&::operator delete));
    std::cout << std::endl;

    return 0;
}


This program does not print 'A'-s from the destructor. Any idea why?
A heads up related to deleting pointers in vector. I know several ways to do it, just wondering why this way it does not work. Checked with g++ 4.4.3 on Ubuntu 10.

Thanks!
Last edited on
I find for_each to be obfuscated in pretty much every situation I've ever seen it in.

You're much better off with a range based for loop here:

1
2
for(auto& i : v)
    delete i;


Much shorter, much simpler, much more clear. Of course for this to work you have to make A's dtor public.



Plus I'm pretty sure ptr_fun is deprecated as of C++11.

EDIT: also, of course, if you're using smart pointers, you don't have to delete anything.


EDIT 2:

And to answer your actual question...

operator delete is different from regular delete.

regular delete calls dtors and frees memory.
operator delete only frees memory.


Try this:

 
operator delete(v[0]);  // does not call dtor 
Last edited on
You are calling funcion operator delete that all what it does is reclaims the storage allocated by the earlier call to operator new.

There is C++ operator delete and there is function operator delete in C++. The function is called by operator delete and can be redefined by the user.

Consider the difference between these code snips

1
2
3
4
5
6
7
8
struct A
{
	~A() { std::cout << "A::~A()\n"; }
};

A *p = new A();

::delete ( p );


Here the operator delete is called that at first calls the class destructor and after that it calls function operator delete..


1
2
3
4
5
6
7
8
struct A
{
	~A() { std::cout << "A::~A()\n"; }
};

A *p = new A();

::operator delete( p );


Here function operator delete is called. It only reclaims the storage.


That to do what you want you can use a lambda expression

std::for_each(v.begin(), v.end(), []( A *p ) { ::delete p; } );

Or you can write the corresponding functional object yourself.
Last edited on
Disch, Vlad,

Thank you for pointing out the difference between operator delete and function operator delete.
One more question: is it possible to get the pointer to the operator delete (::delete) in order to compile this snip?

std::for_each(v.begin(), v.end(), std::ptr_fun(&::delete));

I don't want to use C++11 yet.

Thanks!

P.S. I changed class to struct in my original code.
Last edited on
It may be best to forget ptr_fun() and put your own function in that does the delete. Sometimes the obvious ways are best, especially for maintenance by someone else.
if you provide a null to delete, it does nothing
is it possible to get the pointer to the operator delete

No.

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct A {
    A() { std::cout << "A::A()\n"; }
    ~A() { std::cout << "A::~A()\n"; }
};

// as deleter is templated, it must be declared outide function scope
template<typename T>
struct deleter {
    void operator()(T* ptr) {
        delete ptr;
    }
};

// or use a function (templated or otherwise, they
// need to be declared at global/namespace scope)
//
// template<typename T>
// void deleter(A* ptr) {
//     delete ptr;
// }
//
// call like:
// std::for_each(v.begin(), v.end(), deleter<A>);

int main() {
    //std::vector<A*> v(4, static_cast<A*>(0));
    //
    // static_cast<A*>(0) not needed as zeroing handled by default param
    // provided, e.g. const value_type& val = value_type()
    //
    std::vector<A*> v(4);

    // not templated, so ok at function scope
    struct newer {
        A* operator()() {
            return new A;
        }
    };

    std::generate(v.begin(), v.end(), newer());
    std::cout << std::endl;

    std::for_each(v.begin(), v.end(), deleter<A>());
    std::cout << std::endl;

    return 0;
}


Output:

A::A()
A::A()
A::A()
A::A()

A::~A()
A::~A()
A::~A()
A::~A()
Last edited on
C++11 actually has that functor already, in header <memory>

std::for_each(v.begin(), v.end(), std::default_delete<A>());
Topic archived. No new replies allowed.