std::set deleter in C++ is not working

2019-07-27 04:03发布

问题:

Here I have defined my own deleter , but not sure why isn't working . Second is there any way of not using for_each loop and just defining deleter using it at the time of set declaration makes all objects get deleted automatically when the set object goes out of scope .

#include <iostream>
#include <memory>
#include <string>
#include <set>
#include <algorithm>
using namespace std;
class A
{
    int i;
    public:
    A(int pi):i(pi) {}
    int intake() const { return i; }
    void show() { cout<<i<<endl; }
    ~A() { cout<<"Destructor : "<<i<<endl; }
};
template <typename T>
struct Deleter
{
  void operator () (T *ptr)
  {
     delete ptr;
  }
};
struct A_comp 
{
    bool operator() (const A & lhs, const A & rhs) const
    {
              return lhs.intake() < rhs.intake();
    }
};
int main()
{
   set <A *,A_comp> s;
   s.emplace(new A(40));
   s.emplace(new A(10));
   s.emplace(new A(30));
   s.emplace(new A(20));
   set <A *,A_comp>::iterator it;
   for(it = s.begin(); it != s.end() ; it++)
      (*it)->show();
   for_each (s.begin (), s.end (), Deleter());     // Line 41
   return 0;
}

Compiler Error :

In function 'int main()': 41:43: error: missing template arguments before '(' token In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h: In instantiation of 'std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = A*; _Val = A*; _KeyOfValue = std::_Identity<A*>; _Compare = A_comp; _Alloc = std::allocator<A*>; std::_Rb_tree<_Key, _Val,
_KeyOfValue, _Compare, _Alloc>::key_type = A*]': /usr/include/c++/4.9/bits/stl_tree.h:1748:55:   required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key,
_Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_unique(_Args&& ...) [with _Args = {A*}; _Key = A*; _Val = A*; _KeyOfValue = std::_Identity<A*>; _Compare = A_comp; _Alloc = std::allocator<A*>]' /usr/include/c++/4.9/bits/stl_set.h:453:64:   required from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>,
_Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::emplace(_Args&& ...) [with
_Args = {A*}; _Key = A*; _Compare = A_comp; _Alloc = std::allocator<A*>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename
__gnu_cxx::__alloc_traits<_Allocator>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<A*>]' 34:23:   required from here /usr/include/c++/4.9/bits/stl_tree.h:1445:11: error: invalid user-defined conversion from 'const key_type {aka A* const}' to 'const A&' [-fpermissive]
    __comp = _M_impl._M_key_compare(__k, _S_key(__x));
           ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'const key_type {aka A* const}' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1445:11: error: invalid conversion from 'std::_Rb_tree<A*, A*, std::_Identity<A*>, A_comp, std::allocator<A*> >::key_type {aka A*}' to 'int' [-fpermissive]
    __comp = _M_impl._M_key_compare(__k, _S_key(__x));
           ^ 11:5: note: initializing argument 1 of 'A::A(int)' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1445:11: error: invalid user-defined conversion from 'A* const' to 'const A&' [-fpermissive]
    __comp = _M_impl._M_key_compare(__k, _S_key(__x));
           ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'A* const' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1445:11: error: invalid conversion from 'A*' to 'int' [-fpermissive]
    __comp = _M_impl._M_key_compare(__k, _S_key(__x));
           ^ 11:5: note: initializing argument 1 of 'A::A(int)' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1456:7: error: invalid user-defined conversion from 'A* const' to 'const A&' [-fpermissive]
       if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
       ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'A* const' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1456:7: error: invalid conversion from 'A*' to 'int' [-fpermissive]
       if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
       ^ 11:5: note: initializing argument 1 of 'A::A(int)' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1456:7: error: invalid user-defined conversion from 'const key_type {aka A* const}' to 'const A&' [-fpermissive]
       if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
       ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'const key_type {aka A* const}' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1456:7: error: invalid conversion from 'std::_Rb_tree<A*, A*, std::_Identity<A*>, A_comp, std::allocator<A*> >::key_type {aka A*}' to 'int' [-fpermissive]
       if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
       ^ 11:5: note: initializing argument 1 of 'A::A(int)' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h: In instantiation of 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type) [with _Key = A*; _Val = A*; _KeyOfValue = std::_Identity<A*>; _Compare = A_comp; _Alloc = std::allocator<A*>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<A*>; std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<A*>*]': /usr/include/c++/4.9/bits/stl_tree.h:1750:65:   required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key,
_Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_unique(_Args&& ...) [with _Args = {A*}; _Key = A*; _Val = A*; _KeyOfValue = std::_Identity<A*>; _Compare = A_comp; _Alloc = std::allocator<A*>]' /usr/include/c++/4.9/bits/stl_set.h:453:64:   required from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>,
_Compare, typename __gnu_cxx::__alloc_traits<_Allocator>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::emplace(_Args&& ...) [with
_Args = {A*}; _Key = A*; _Compare = A_comp; _Alloc = std::allocator<A*>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename
__gnu_cxx::__alloc_traits<_Allocator>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<A*>]' 34:23:   required from here /usr/include/c++/4.9/bits/stl_tree.h:1693:8: error: invalid user-defined conversion from 'A* const' to 'const A&' [-fpermissive]
        || _M_impl._M_key_compare(_S_key(__z),
        ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'A* const' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1693:8: error: invalid conversion from 'A*' to 'int' [-fpermissive]
        || _M_impl._M_key_compare(_S_key(__z),
        ^ 11:5: note: initializing argument 1 of 'A::A(int)' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1693:8: error: invalid user-defined conversion from 'A* const' to 'const A&' [-fpermissive]
        || _M_impl._M_key_compare(_S_key(__z),
        ^ 11:5: note: candidate is: A::A(int) <near match> 11:5: note:   no known conversion for argument 1 from 'A* const' to 'int' In file included from /usr/include/c++/4.9/set:60:0,
                 from 4: /usr/include/c++/4.9/bits/stl_tree.h:1693:8: error: invalid conversion from 'A*' to 'int' [-fpermissive]
        || _M_impl._M_key_compare(_S_key(__z),
        ^ 11:5: note: initializing argument 1 of 'A::A(int)'

回答1:

The code provided doesnt compile for a few reasons :

  1. Missing template argument in Deleter
  2. Your comparitor compares A when it needs to compare A*

If you dont use pointers then your objects will be deleted when the set goes out of scope.

Alternativly you can use std:unique_ptr, code ammended below :

#include <iostream>
#include <memory>
#include <string>
#include <set>
#include <algorithm>
using namespace std;
class A
{
    int i;
    public:
    A(int pi):i(pi) {}
    int intake() const { return i; }
    void show() { cout<<i<<endl; }
    ~A() { cout<<"Destructor : "<<i<<endl; }
};
template <typename T>
struct Deleter
{
  void operator () (T *ptr)
  {
     delete ptr;
  }
};
struct A_comp 
{
    bool operator() (const std::unique_ptr<A>& lhs, const std::unique_ptr<A>& rhs) const
    {
              return lhs->intake() < rhs->intake();
    }
};
int main()
{
   set <std::unique_ptr<A> ,A_comp> s;
   s.emplace(std::unique_ptr<A>(new A(40)));
   s.emplace(std::unique_ptr<A>(new A(10)));
   s.emplace(std::unique_ptr<A>(new A(30)));
   s.emplace(std::unique_ptr<A>(new A(20)));
   for(auto it = s.begin(); it != s.end() ; it++)
      (*it)->show();
   return 0;
}