目前,我正在使用动态库进行测试,并且在数据管理/删除方面遇到了一些麻烦...我如何“通知”指针其无效?
我需要:线程安全的方法,从其库中删除数据并使DataContainers Ptr无效或线程安全的解决方法。
我尝试过的事情:
使用共享/弱指针=任何人都可以删除它(库已卸载,但是指针仍然存在于另一个库中并在那里删除了,但不知道如何。)
可能的解决方案:-保留DataContainer的列表,并在“库卸载”上将其手动设置为nullptr。-不要使用Ptr,使用索引来定位位置并在每次需要数据时进行查找。
简单示例:
class Data
{
public:
Data(std::string Str) : SomeStr(Str) {}
std::string SomeStr;
};
struct DataContainer
{
Data* m_Data = nullptr;
};
int main()
{
// This vector is static inside a Dynamic Library so we need to use UniquePtr,
// to be sure it gets deleted inside its Library when unloaded
// if we could use SharedPtr/WeakPtr it would be too easy... but it could get deleted by anyone
// Protected by Mutex
std::vector<std::unique_ptr<Data>> DataHolder;
DataHolder.push_back(std::make_unique<Data>("Example Str"));
// this could maybe inside another Dynamic Library
DataContainer Container;
Container.m_Data = (*DataHolder.begin()).get();
// As example instead of using a Dynamic Library that would get unloaded here
DataHolder.clear();
// Cannot use m_Data here, it got deleted by the DataHolder but Container don't know that
std::cout << "Str: " << Container.m_Data->SomeStr << std::endl;
return 0;
}
shared_ptr
/ weak_ptr
是您需要的。保留所有权的模块具有shared_ptr
个对象,但允许其他人仅获取weak_ptr
个对象。其他模块(不应该拥有所有权的模块)每次需要数据时都必须临时从shared_ptr
中获取weak_ptr
,并且它们有义务在访问数据后立即销毁每个shared_ptr。
如果不保留此不变式,则需要在模块之间进行一些外部同步,例如onPointerInvalidated
,但这是更糟糕的设计。
关于线程安全,如果您将shared_ptr保留在该对象上,那么任何人都无法销毁该对象(除非有人进行诸如delete shared_ptr_.get()
的恶意操作)。这暗示着使用者与所有者之间的契约:使用者在很短的时间内锁定了shared_ptr(因此延迟了销毁(如果有的话)),而所有者删除对象则不用担心任何悬空的指针。
我同意,我认为共享/弱指针应该可以解决问题。这就是我的实现方式:
class Data
{
public:
Data(std::string Str) : SomeStr(Str) {}
std::string SomeStr;
};
struct DataHolder {
std::vector<std::shared_ptr<Data>> data;
std::weak_ptr<Data> get_data(size_t idx) {
return std::weak_ptr<Data>(data[idx]);
}
};
struct DataContainer
{
std::weak_ptr<Data> m_Data;
};
int main()
{
// This vector is static inside a Dynamic Library so we need to use UniquePtr,
// to be sure it gets deleted inside its Library when unloaded
// if we could use SharedPtr/WeakPtr it would be too easy... but it could get deleted by anyone
// Protected by Mutex
DataHolder theDataHolder;
theDataHolder.data.push_back(std::make_shared<Data>("Example Str"));
DataContainer Container;
Container.m_Data = theDataHolder.get_data(0);
// container is passed to a method inside the shared lib
auto t = shared_lib_entry(Container);
std::this_thread::sleep_for(2s);
// As example instead of using a Dynamic Library that would get unloaded here
theDataHolder.data.clear();
wait_for_completion(t);
return 0;
}
// INSIDE the SHAERD LIB
std::thread shared_lib_entry(DataContainer &aContainer) {
std::cout << "Entry in the lib: " << private_var << std::endl;
std::thread aThread([&](){
std::cout << "in the thread start" << std::endl;
int count = 5;
while (count-- > 0) {
std::cout << "in the thread ["<< count <<"]" << std::endl;
if (aContainer.m_Data.expired()) {
std::cout << "Someone killed the src " << std::endl;
} else {
auto sp = aContainer.m_Data.lock();
std::cout << "Str: " << sp->SomeStr << std::endl;
}
std::this_thread::sleep_for(1s);
}
});
std::cout << "Thread finished " << private_var << std::endl;
return aThread;
}