I'm currently write a weak reference resource manager as below, and the compiler complained Manager has a private constructor.
My question is that: why can't I access the private member function in the static function?
#ifndef TENSOR_MANAGER_H
#define TENSOR_MANAGER_H
#include <memory>
#include <functional>
#include <map>
#include <iostream>
template<typename key_t, typename model_t>
class Manager : public std::enable_shared_from_this<Manager<key_t, model_t> > {
public:
using self_t = Manager<key_t, model_t>;
public:
static auto Create() {
return std::make_shared<self_t>();
}
public:
std::shared_ptr<model_t> GetOrAdd(const key_t &&key, const char *data, size_t size) {
auto pos = m_resources.find(key);
std::shared_ptr<model_t> tmp;
if (pos != m_resources.end()) {
tmp = pos->second.lock();
}
if (!tmp) {
model_t *p = new model_t();
auto deletor = std::bind(&self_t::releaseItem,
std::weak_ptr<self_t>(this->shared_from_this()),
key,
std::placeholders::_1);
tmp = std::shared_ptr<model_t>(p, deletor);
m_resources[key] = std::weak_ptr<model_t>(tmp);
}
return tmp;
}
public:
void Print() {
std::cout << "Content: ";
for (const auto &item : m_resources) {
std::cout << item.first << " ";
}
std::cout << std::endl;
}
private:
static void releaseItem(std::weak_ptr<self_t> self, const key_t &key, model_t *p) {
std::shared_ptr<Manager<key_t, model_t>> mgr = self.lock();
if (mgr) {
mgr->m_resources.erase(key);
}
delete p;
}
private:
std::map<key_t, std::weak_ptr<model_t> > m_resources;
Manager() = default;
};
#endif //TENSOR_MANAGER_H
Now the compiler gives the errors:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:2043:66: error: field of type 'Manager<std::__1::basic_string<char>, int>' has private default constructor
_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {}
As per Cppreference, the notes on make_shared
clearly state that:
std::shared_ptr<T>(new T(args...))
may call a non-public constructor ofT
if executed in context where it is accessible, whilestd::make_shared
requires public access to the selected constructor.
Since the selected constructor in this case is private
, compilation fails.
If you still wish to keep it private
use the form std::shared_ptr<T>(new T(args...))
in the static
function Create
.
EDIT:
If you are intent on using make_shared
and also a private
constructor, you can employ this hack which uses an empty nested class
and an explicit
constructor.
A minimal example.
#include <memory>
class Bar : public std::enable_shared_from_this<Bar>
{
private:
class Foo {};
Bar() = default;
public:
static auto Create() {
return std::make_shared<Bar>(Foo());
}
explicit Bar(Foo);
};
int main()
{
auto i = Bar::Create();
}
See DEMO.
You can adapt the above to your requirement.
Because it is the library function std::make_shared
that is invoking private constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With