1

I want to use a boost::ptr_map inside a specific class which stores instances of itself. However, please consider the following example:

#include <boost/checked_delete.hpp>
#include <boost/ptr_container/ptr_map.hpp>


class foo
{
    friend void boost::checked_delete<>(foo*);
    ~foo() {}
};


int main()
{
    boost::checked_delete(new foo);     // OK
    boost::ptr_map<int, foo> foo_map;   // error C2248: 'foo::~foo' : cannot access private member declared in class 'foo'

    return 0;
}

The error happens at the following line

// verify that types are complete for increased safety

template<class T> inline void checked_delete(T * x)
{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;    // error C2248
}

What exactly is going on here? Shouldn't it work? I assume that the problem is that templates are defined in the compilation unit they are included in and boost::checked_delete is called from another compilation unit in the implementation source of bosst::ptr_map. So, it's not the same function I declared as a friend.

However, is there a workaround for this problem?

0xbadf00d
  • 17,405
  • 15
  • 67
  • 107

2 Answers2

2

Try this syntax when declaring the friend:

template <class T> friend void boost::checked_delete(T*);

bshields
  • 3,563
  • 16
  • 16
  • 1
    The most explicit (so preferable) syntax would be `friend void boost::checked_delete<>(foo*);` or `friend void boost::checked_delete(foo*);`. That's why I'm using it. But thanks for your approach. – 0xbadf00d Jun 15 '11 at 07:46
  • The comment is right on target, the syntax in the question befriends a single template instantiation, while the proposed solution befriends all the instantiations, which can be problematic. Consider reading [this](http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class/4661372#4661372) and [this](http://stackoverflow.com/questions/1810753/overloading-operator-for-a-templated-class/1811208#1811208) other answers to different questions. – David Rodríguez - dribeas Jun 15 '11 at 08:13
1

Here is the start of the huge error message* from GCC, which is the start of the chain of instantiations (usually, and in this case):

In file included from main.cpp:1:0: main.cpp: In function 'void boost::checked_delete(T*) [with T = const foo]':

Adding

friend void boost::checked_delete<>(foo const*);

makes the code compile.

(*): 13 lines and 3510 characters for 270 chars/line

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Thanks for your answer. Sorry, for didn't mention that, but I already noticed it. If you add the const modifier it will work, but I thought this could be less portable (I'm using MSVC 10.0). Or is it guaranteed to be const? – 0xbadf00d Jun 15 '11 at 07:44
  • @FrEEzE2046 It's not so much an issue of portability but of what the code that uses `boost::checked_delete` does: passing pointers to `const` or not to it. So you'll have to check with the docs for `ptr_map` to see if there's any guarantee. – Luc Danton Jun 15 '11 at 07:55
  • @FrEEze2046: If you go back and read the error message, it will tell you what the library does, which is independent of which compiler you are using. – David Rodríguez - dribeas Jun 15 '11 at 08:09
  • Wouldn't it be possible to make ´checked_delete´ a friend of foo with all possible modifiers? – 0xbadf00d Jun 15 '11 at 08:17
  • @FrEEzE2046 No; it's either the template as a whole or select specializations. There's no way to express *cv* qualification as a template specialization (i.e. match any *cv* `foo`) and partial specialization is not allowed for function templates anyway. – Luc Danton Jun 15 '11 at 08:22