Liebe Leserinnen, liebe Leser,
es gibt Fälle, wenn man den privaten Konstruktor einer Klasse mit einer der Smart-Pointer erzeugenden Funktionen der Standardbibliothek benutzen muss, aber das ist leider nicht so einfach zu tun. Ein einfaches Beispiel gibt es hier unten:
C++
1
2
3
4
5
6
7
8
9
10
// someclass.h
class SomeClass {
public:
static std::shared_ptr<SomeClass> getInstance();
// other funtions
private:
SomeClass();
};
C++
1
2
3
4
5
6
7
8
9
// someclass.cpp
std::shared_ptr<SomeClass> SomeClass::getInstance()
{
auto instance = std::make_shared<SomeClass>();
// do something with instance
return instance;
}
Das sieht gut aus, aber die std::make_shared Funktion kann auf den privaten Konstruktor von SomeClass nicht zugreifen, und deswegen kann die Klasse nicht erzeugt werden. Der Fehlermeldung des Compilers sagt die gleiche Sache:
make
1
2
/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.0/include/g++-v7/bits/unique_ptr.h:825:30: error: ‘SomeClass::SomeClass()’ is private within this context
{ return shared_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
Glücklicherweise ist eine Umgehung für dieses Problem mithilfe einer kleinen Vererbungszauberei möglich:
C++
1
2
3
4
5
6
7
8
9
10
// updated someclass.cpp
std::shared_ptr<SomeClass> SomeClass::getInstance()
{
struct MkShrdEnablr : public SomeClass {};
auto instance = std::make_shared<MkShrdEnablr>();
// do something with instance
return instance;
}
Wenn eine temporäre Klasse zu der getInstance() Funktion hinzugefügt wird, die aus SomeClass abgeleitet wurde, führt das zu dem ursprünglichen Ziel. Das ist auch bemerkenswert, dass das Vorhandensein einer temporären Klasse zu der Welt nicht freigelegt ist, weil das Rückgabewert weiterhin nur ein Pointer zu SomeClass ist, also alles wird in der urpsrünglichen Klasse zurückgewandelt, sobald die Funktion zurückkehrt.
Die Lektion des Tages ist:
Verwende eine temporäre Klasse, um eine Verbindung zwischen der Smart-Pointer erzeugenden Funktion und einer Klasse mit privatem Konstruktor zu etablieren.