说我有一个'Car'
类,带有一个复杂的子目录树。每个类都有一个唯一的ID。我有一个管理类,该类跟踪所有汽车的指针,并可以基于id
查找它们。
class Car {
public:
using CarId = size_t;
Car* getCar(CarId id) const { return sMap[id]; }
Car(){
sMutex.lock();
mId = ++sLastId;
sMap.insert(pair(mId,this));
sMutex.unlock();
}
private:
static map<CarId,Car*> sMap;
static CarId sLastId;
static mutex sMutex;
CarId mId;
}
我想对此进行重构,以便Car::getCar
返回weak_ptr<Car>
,因为返回原始指针会带来很多麻烦。
但是,要以一种幼稚的方式从构造函数向sMap
中添加指向其自身的弱指针,则需要创建一个共享指针,该指针会在对象超出范围时立即破坏该对象:
sMutex.lock();
mId = ++sLastId;
sMap.insert(
pair(mId,
weak_ptr<Car>(shared_ptr(this))
)
);
sMutex.unlock();
该死,我想我需要使用一些工厂:
class CarFactory {
public:
shared_ptr<Car> createCar(){
sMutex.lock();
mId = ++sLastId;
auto res = shared_ptr<Car>(this);
sMap.insert(
pair(mId,
weak_ptr<Car>(res)
)
);
sMutex.unlock();
return result;
}
private:
map<CarId,Car*> sMap;
CarId sLastId;
mutex sMutex;
}
很好,但是模块中有很多派生类,很多时候我无法从此处包括这些类,因此我无法为此处定义的每种可能的Car派生类型提供一个工厂方法,这是非常不切实际的。但是,我需要跟踪每辆汽车,我不允许任何方式创建不通过工厂方法的派生汽车。
到目前为止我提出的最好的解决方案:
class CarFactory {
...
template<class DT, class Tp>
shared_ptr<DT> create(Tp params...)
{
sMutex.lock();
mId = ++sLastId;
auto res = shared_ptr<Car>(new DT(forward(params)...) );
sMap.insert(
pair(mId,
weak_ptr<Car>(res)
)
);
sMutex.unlock();
return result;
}
...
}
允许私有化派生类的构造函数:
class VolksWagenGolf : public VolksWagen {
friend class CarFactory;
private:
VolksWagen(bool enableEmissionCheat);
}
因此,我只能按以下方式创建它:
shared_ptr<Car> myCar = CarFactory::create<VolksWagenGolf>(true);
对,但是我仍然不喜欢它,因为:
因此,如果您有任何想法如何实现这种模式,即必须通过集中簿记机制创建每个派生类,同时使用弱指针进行跟踪,请告诉我。
答案 0 :(得分:1)
第1步:创建受保护的汽车构造函数。它需要由您的工厂功能拥有的令牌:只有工厂功能才有权创建该令牌。
现在,没有该令牌,没有试图创建派生汽车的代码。
class CarFactory {
private:
struct CarConstructionPermission {
explicit CarConstructionPermission(int) {};
};
friend class Car;
public:
template<class D, class...Args>
std::shared_ptr<D> create(Args&&...args) {
// blah blah
auto retval = std::make_shared<D>( CarConstructionPermission(0), std::forward<Args>(args)... );
// blah
return retval;
}
};
class Car {
protected:
explicit Car(CarConstructionPermission) {}
};
第2步:使模板主体部分隐藏。
您需要的是一个从()到shared_ptr的函数。
private:
bool create_internal(std::function< std::shared_ptr<Car>() > producer);
public:
template<class D, class...Args>
std::shared_ptr<D> create(Args&&...args) {
std::shared_ptr<D> retval;
if (create_internal([&]{
retval = std::make_shared<D>( CarConstructionPermission(0), std::forward<Args>(args)... );
return retval;
}) {
return retval;
}
return {}; // failure
}
现在所有互斥对象都在create_internal
内部;我们输入橡皮擦创建汽车并将其传递。
create_internal
现在看起来很像您的create
,但它不是模板,返回bool
,并接受1个参数。 auto result = producer();
替换了shared_ptr<Car>
行。