Posso usare boost :: make_shared con un costruttore privato?
-
25-09-2019 - |
Domanda
Si consideri il seguente:
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>();
};
};
Sembra DirectoryIterator dovrebbe essere in grado di chiamare boost::make_shared<DirectoryIteratorImpl>
, perché è un amico di DirectoryIteratorImpl
. Tuttavia, questo codice non riesce a compilare poiché il costruttore per DirectoryIteratorImpl è privato.
Dal momento che questa classe è un dettaglio interno di implementazione che i clienti di DirectoryIterator
non dovrebbero mai toccare, sarebbe bello se potessi mantenere il costruttore privato.
E 'questo il mio equivoco fondamentale attorno make_shared
o ho bisogno di segnare una sorta di pezzo spinta come friend
in modo che la chiamata a compilare?
Soluzione
sarà davvero bisogno di fare qualche amico pezzi spinta per questo. Fondamentalmente make_shared
sta chiamando il costruttore e il fatto che questo viene fatto all'interno di una funzione amico non importa per il compilatore.
La notizia buona è però che make_shared
chiama il costruttore, non qualsiasi altro pezzo. Quindi, solo facendo amico make_shared
avrebbe funzionato ... Tuttavia ciò significa che chiunque potrebbe quindi creare un shared_ptr<DirectoryIteratorImpl>
...
Altri suggerimenti
C'è una ragione buona per non usare il buon vecchio costruttore shared_ptr
? (Se c'è una, si potrebbe desiderare di dare un'occhiata al l'attuazione make_shared
e farlo)
DirectoryIterator()
: impl( new detail::DirectoryIteratorImpl() )
{}
In questo modo la chiamata al costruttore è fatto dalla classe DirectoryIterator
che è già amico di DirectoryIteratorImpl
senza aprire la porta per tutti gli altri codici.
È possibile suddividere la classe in parte di interfaccia e parte implementazione. La parte interfaccia è resa pubblica, e la parte implementazione può avere costruttori pubblici. Tuttavia, questo significa che devi utilizzare l'ereditarietà virtuale.