gpt4 book ai didi

c++ - 不控制派生类的线程安全工厂模式

转载 作者:行者123 更新时间:2023-11-30 04:58:44 24 4
gpt4 key购买 nike

假设我有一个类 'Car'有一个复杂的子类树。每个类(class)都有一个唯一的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;
}
...
}

允许私有(private)化派生类构造函数:

class VolksWagenGolf : public VolksWagen {
friend class CarFactory;
private:
VolksWagen(bool enableEmissionCheat);
}

因此我只能按如下方式创建它:

shared_ptr<Car> myCar = CarFactory::create<VolksWagenGolf>(true);

是的,但我还是不喜欢它,因为:

  1. 这是一个模板,出于各种原因,最好不要使用模板。
  2. 任何时候,一个不知道这种机制的同事都可以来声明一个带有公共(public)构造函数的新 Car 类型,就像他过去经常做的那样。但现在当他使用那个公共(public)构造函数时,他的汽车将不会被跟踪。

因此,如果您有任何想法如何实现这样一种模式,即必须通过集中簿记机制创建每个派生类,同时使用弱指针进行跟踪,请告诉我。

最佳答案

第 1 步:创建 protected 汽车构造函数。它需要一个由您的工厂函数拥有的 token :只有工厂函数有权创建该 token 。

现在没有该 token ,任何试图创建派生汽车的代码都不能。

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里面了;我们输入 erase creating the car 并将其传入。

create_internal现在看起来很像你的 create , 但不是模板,返回 bool , 并接受 1 个参数。 auto result = producer();替换 shared_ptr<Car>行。

关于c++ - 不控制派生类的线程安全工厂模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51544534/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com