c++ - ¿Puedo usar boost:: make_shared con un constructor privado?
shared-ptr make-shared (3)
Considera lo siguiente:
class DirectoryIterator;
namespace detail {
class FileDataProxy;
class DirectoryIteratorImpl
{
friend class DirectoryIterator;
friend class FileDataProxy;
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring root;
DirectoryIteratorImpl();
explicit DirectoryIteratorImpl(const std::wstring& pathSpec);
void increment();
bool equal(const DirectoryIteratorImpl& other) const;
public:
~DirectoryIteratorImpl() {};
};
class FileDataProxy //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator.
{
friend class DirectoryIterator;
boost::shared_ptr<DirectoryIteratorImpl> iteratorSource;
FileDataProxy(boost::shared_ptr<DirectoryIteratorImpl> parent) : iteratorSource(parent) {};
public:
std::wstring GetFolderPath() const {
return iteratorSource->root;
}
};
}
class DirectoryIterator : public boost::iterator_facade<DirectoryIterator, detail::FileDataProxy, std::input_iterator_tag>
{
friend class boost::iterator_core_access;
boost::shared_ptr<detail::DirectoryIteratorImpl> impl;
void increment() {
impl->increment();
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
detail::FileDataProxy dereference() const {
return detail::FileDataProxy(impl);
};
public:
DirectoryIterator() {
impl = boost::make_shared<detail::DirectoryIteratorImpl>();
};
};
Parece que DirectoryIterator debería poder llamar a boost::make_shared<DirectoryIteratorImpl>
, porque es amigo de DirectoryIteratorImpl
. Sin embargo, este código no se puede compilar porque el constructor de DirectoryIteratorImpl es privado.
Dado que esta clase es un detalle de implementación interna que los clientes de DirectoryIterator
nunca deberían tocar, sería bueno si pudiera mantener el constructor privado.
¿Este es mi malentendido fundamental sobre make_shared
o necesito marcar algún tipo de impulso como friend
para que compile la llamada?
¿Hay alguna buena razón para no usar el buen viejo constructor shared_ptr
? (Si hay uno, es posible que desee echar un vistazo a la implementación make_shared
y hacerlo)
DirectoryIterator()
: impl( new detail::DirectoryIteratorImpl() )
{}
De esta forma, la llamada al constructor se hace desde la clase DirectoryIterator
que ya es amiga de DirectoryIteratorImpl
sin abrir la puerta a todos los demás códigos.
De hecho, necesitarás hacer algunas piezas de impulso amigo para esto. Básicamente make_shared
está llamando al constructor y el hecho de que esto se hace desde dentro de una función de amigo no es importante para el compilador.
La buena noticia es que make_shared
llama al constructor, no a ninguna otra pieza. Así que solo hacer make_shared
friend funcionaría ... Sin embargo, significa que cualquiera podría crear un shared_ptr<DirectoryIteratorImpl>
...
Puede dividir su clase en parte de la interfaz y parte de implementación. La parte de interfaz se hace pública, y la parte de implementación puede tener constructores públicos. Sin embargo, eso significa que debe usar herencia virtual.