Должно ли это компилироваться (вложенные private классы)? в избранное  новое горячее всё    подписка   модер. 
От: Xentraxhttp://www.lanovets.ru
Дата: 29.05.08 17:09
Имеем вложенный закрытый класс с пользовательским оператором delete. Попытка использовать std::tr1::shared_ptr<> обламывается в VC2008 на шаблонной функции. Вот упрощенный пример:

#include <cstdlib> 

template <typename T> void destroy(T* ptr) 
{ 
  delete ptr; // line #5 
} 

class A 
{ 
private: 
  class B 
  { 
  public: 
    void test() 
    { 
        B* p = new B; 
        destroy(p); 
    } 

    ~B() 
    { 
    } 

    void* operator new(size_t size) 
    { 
        return malloc(size); 
    } 

    void operator delete(void* p, size_t /*size*/) 
    { 
        free(p); 
    } 
  }; 
};



Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

cl15.cpp
cl15.cpp(5) : error C2248: 'A::B' : cannot access private class declared in class 'A'
cl15.cpp(12) : see declaration of 'A::B'
cl15.cpp(9) : see declaration of 'A'
cl15.cpp(17) : see reference to function template instantiation 'void destroy<A::B>(T *)' being compiled
with
[
T=A::B
]



Вот так вариант с shared_ptr<>

#include <cstdlib> 
#include <memory>

class A 
{ 
private: 
  class B 
  { 
  public: 
    void test() 
    { 
        std::tr1::shared_ptr<B> b(new B());
    } 

    ~B() 
    { 
    } 

    void* operator new(size_t size) 
    { 
        return malloc(size); 
    } 

    void operator delete(void* p, size_t /*size*/) 
    { 
        free(p); 
    } 
  }; 
};
Re: Должно ли это компилироваться (вложенные private классы) в избранное  новое    модер. 
От: Roman Odaisky 
Дата: 29.05.08 18:18
Здравствуйте, Xentrax, Вы писали:

X>Имеем вложенный закрытый класс с пользовательским оператором delete. Попытка использовать std::tr1::shared_ptr<> обламывается в VC2008 на шаблонной функции.


In strict mode, with -tused, Compile succeeded (but remember, the Comeau online compiler does not link).


А ошибки всё же есть :-)
X>#include <cstdlib>
X> return std::malloc(size);

хотя и несерьезные.
status=sent (delivered to file: /dev/null)
Re[2]: Должно ли это компилироваться (вложенные private клас в избранное  новое    модер. 
От: Xentraxhttp://www.lanovets.ru
Дата: 29.05.08 19:31
Здравствуйте, Roman Odaisky, Вы писали:

RO>А ошибки всё же есть

X>>#include <cstdlib>
X>> return std::malloc(size);
RO>хотя и несерьезные.

как мы видим, компилятору Comeau доверять нельзя. Я ведь к нему сразу и пошел, но он спокойно скомпилировал.
Теперь для забивания бага в MS Connect хотелось бы понять откуда следует, что у функции destroy<> есть доступ к ~B()
Re[2]: Должно ли это компилироваться (вложенные private клас в избранное  новое    модер. 
От: Bell 
Дата: 29.05.08 19:35
Оценка:4 (1)
Здравствуйте, Roman Odaisky, Вы писали:


RO>

In strict mode, with -tused, Compile succeeded (but remember, the Comeau online compiler does not link).


А чем Комо руководствуется в данном случае?
Почему можно явно инстанциировать destroy для A::B:
template void destroy<A::B>(A::B* ptr);//Ок

но нельзя специализировать?
template<>
void destroy<A::B>(A::B* ptr)
{
   delete ptr;
}


Кстати вот еще интересный момент:
template <typename T> void destroy(T* ptr) 
{ 
  delete ptr; // line #5 
} 

class A 
{ 
private: 
  class B 
  { 
  public: 
    void test() 
    { 
        B* p = new B; 
        //destroy(p); 
    } 

    ~B() 
    { 
    } 
  }; 

  friend int main();
};


int main()
{
   destroy(new A::B());//Ок!!!
   return 0;
}


Любите книгу — источник знаний (с) М.Горький
Re: Должно ли это компилироваться (вложенные private классы) в избранное  новое    модер. 
От: Bell 
Дата: 29.05.08 20:02
Здравствуйте, Xentrax, Вы писали:

VC7.1 тоже не компилит.
Хотел предложить тебе сделать std::tr1::destroy<A::B> другом A, но мой VC7.1 и это не съел:

class A 
{ 
private: 
    
  class B 
  { 
  public: 
    void test() 
    { 
        boost::shared_ptr<B> b(new B());
    } 

    ~B() 
    { 
    } 
  }; 

  friend void boost::checked_delete<A::B>(A::B *);//error C2248: 'A::B' : cannot access private class declared in class 'A'
};




Вот более простой вариант с этой же проблемой:
namespace N
{
   template <class T>
   void destroy(T* ptr)
   {
      delete ptr;
   }
}

class A 
{
private: 
    
  class B 
  { 
  public: 
    void test() 
    { 
       N::destroy(new B());
    } 

    ~B() 
    { 
    } 
  }; 

  friend void N::destroy<A::B>(A::B *);//error C2248: 'A::B' : cannot access private class declared in class 'A'
};


Зато компилится вот такой вот вариант:
template <typename T> 
void my_destroy(T* ptr) 
{ 
  delete ptr; // line #5 
} 

class A 
{ 
private: 
  class B 
  { 
  public: 
    void test() 
    { 
        boost::shared_ptr<B>(new B(), my_destroy<A::B>);
    } 

    ~B() 
    { 
    } 

    void* operator new(size_t size) 
    { 
        return malloc(size); 
    } 

    void operator delete(void* p, size_t /*size*/) 
    { 
        free(p); 
    } 
  };

  friend void my_destroy<A::B>(A::B*);
};


Любите книгу — источник знаний (с) М.Горький
Re[2]: Должно ли это компилироваться (вложенные private клас в избранное  новое    модер. 
От: Xentraxhttp://www.lanovets.ru
Дата: 29.05.08 20:58
Здравствуйте, Bell, Вы писали:

У нас импользуется порезаный shared_ptr, без deleter'ов. Дело в том, что в бусте пользовательские функции удаления реализованы через класс с виртуальными функциями, а вируальные функции в шаблонах не совместимы с выгрузкой DLL из памяти (FreeLibrary). Я задавал вопрос по этому поводу в c++.moderated, там меня послали, сказав, что это баг в реализации. Я другого способа реализовать shared_ptr в обычном компиляторе не вижу, поэтому на мой взгляд это у них самих баг в реализации. Но, конечно, скопировать и перекроить исходники shared_ptr никто не запрещает.



B>VC7.1 тоже не компилит.

B>Хотел предложить тебе сделать std::tr1::destroy<A::B> другом A, но мой VC7.1 и это не съел:

Workaround для 8.0 и 9.0 мы еще вчера (уже даже позавчера) нашли. Работает вот так
friend void sp::destroy<B>(B*);


Правда выдает дикий ворнинг 4-го уровня

warning C4396: 'sp::destroy' : the inline specifier cannot be used when a friend declaration refers to a specialization of a function template

#include <cstdlib> 

namespace sp
{
  template <typename T> inline void destroy(T* ptr) 
  { 
    delete ptr; // line #5 
  }

  template <typename T>
  class ptr
  {
    T* p_;
  public:
    ptr(T* p)
      :p_(p)
    {
    }

    ~ptr()
    {
      destroy(p_);
    }
  };
}

class A 
{ 
private: 
  class B 
  { 
  public:

    void test() 
    { 
      sp::ptr<B> p(new B());
    } 

    ~B()
    {
    }

    void* operator new(size_t size) 
    { 
      return malloc(size); 
    } 

    void operator delete(void* p, size_t /*size*/) 
    { 
      free(p); 
    } 
  };

  friend void sp::destroy<B>(B*);
};
Re[3]: Должно ли это компилироваться (вложенные private клас в избранное  новое    модер. 
От: Bell 
Дата: 30.05.08 05:19
Здравствуйте, Xentrax, Вы писали:

X>Правда выдает дикий ворнинг 4-го уровня


X>warning C4396: 'sp::destroy' : the inline specifier cannot be used when a friend declaration refers to a specialization of a function template


Попробуй убрать inline из определения sp::destroy — для шаблонов он все равно особой нагрузки не несет...
Любите книгу — источник знаний (с) М.Горький