提问人:Fewnity 提问时间:6/18/2023 更新时间:6/18/2023 访问量:112
悬空指针问题 C++
Dangling pointer issue C++
问:
我正在制作一个游戏引擎,但我遇到了破坏元素的问题。
例如,我有一些摄像机可以跟踪并观察目标(游戏对象或演员)。 在游戏的后期,相机目标被销毁,相机代码将崩溃,因为代码将尝试访问释放的对象,我想避免这种崩溃。
所以这里有一个简化的代码示例:
我有一个实例化的对象,例如一个 int,以保持简单。
我有几个对这个对象的引用。
如果实例化的对象被删除,我希望能够检查该对象是否仍然存在,如果我的一个脚本想要访问已销毁的对象。
int* refToMyInt = nullptr; //I want to possibility to have empty pointer
int* refToMyInt2 = nullptr;
int* myInt = new int(2);
refToMyInt = myInt;
refToMyInt2 = refToMyInt;
delete myInt;
if(refToMyInt == nullptr && refToMyInt2 == nullptr)
std::cout << "myInt Deleted!" << std::endl; // Never called
除了它不起作用之外,delete 似乎并没有将变量更改为 .
我不想手动设置和 nullptr,因为我可以对该对象进行数十次引用。
我找到了一个解决方案,但它是要使用的,我想避免使用它,因为每次都使用该函数访问值有点麻烦且不切实际......nullptr
refToMyInt
refToMyInt2
weak_ptr
lock()
还有其他解决方案吗?谢谢!
答:
-1赞
Pepijn Kramer
6/18/2023
#1
这些示例将向您展示 vector/make_unique 的更多预期用途。
#include <memory>
#include <iostream>
#include <vector>
// dynamic memory allocation is mostly only necessary
// for polymorphic classes (e.g. classes derived from
// an abstract baseclass)
class my_interface
{
public:
virtual void do_something() = 0;
virtual ~my_interface() = default;
protected:
my_interface() = default;
};
//
class my_concrete_class :
public my_interface
{
public:
my_concrete_class() = default;
// to show my_concrete_class
// instance will be deleted by smart pointer.
~my_concrete_class()
{
std::cout << "my_concrete_class destructor\n";
}
void do_something() override
{
}
};
int main()
{
int my_int{ 1 };
int& ref_to_my_int{ my_int }; // no & this ensure a ref is always refering to a valid object
int* ptr_to_my_int{ &my_int }; // non-owning pointer https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning
ref_to_my_int = 42; // modify through reference
std::cout << "my_int now has value " << my_int;
// create a scope that determines life cycle of my_concrete_class.
{
std::cout << "entering scope 1\n";
std::unique_ptr<my_interface> itf_ptr{ std::make_unique<my_concrete_class>() };
std::cout << "going out of scope , unique_ptr will be destructed\n";
}
{
std::vector<int> values{ 1,2,3 }; // will dynamically allocate memory for 3 ints
std::cout << "vector going out of scope, will delete allocated memory\n";
}
return 0;
}
0赞
Toggy Smith
6/18/2023
#2
“我想避免使用它,因为每次都使用 lock() 函数访问值有点麻烦且不切实际。”
对于 vs 来说,这可能是正确的,但这是一个错误的比较。在取消引用之前,您应该始终检查它是否是:*(ptr.lock())
*ptr
ptr
nullptr
if (ptr != nullptr) {
auto value = *ptr;
}
这仅比以下情况略显冗长:
if (auto sptr = ptr.lock()) {
auto value = *sptr;
}
答:
解决方案是 和 的组合。std::shared_ptr
std::weak_ptr
而不是:
int* refToMyInt = nullptr; //I want to possibility to have empty pointer
int* refToMyInt2 = nullptr;
int* myInt = new int(2);
refToMyInt = myInt;
refToMyInt2 = refToMyInt;
delete myInt;
if(refToMyInt == nullptr && refToMyInt2 == nullptr)
std::cout << "myInt Deleted!" << std::endl; // Never called
你可以写:
std::weak_ptr<int> refToMyInt;
std::weak_ptr<int> refToMyInt2;
std::shared_ptr<int> myInt{ new int(2) };
refToMyInt = std::weak_ptr<int>(myInt);
refToMyInt2 = std::weak_ptr<int>(myInt);
myInt.reset();
if(refToMyInt.expired() && refToMyInt2.expired())
std::cout << "myInt Deleted!" << std::endl; // Never called
我保留了原始变量名称,以便于比较。
评论
delete
不修改指针。std::make_unique
。请参阅 R.11 C++ 核心指南。现在我只希望在数据结构类中看到新的/删除。我看到的任何原始指针我都希望是非拥有的(或者如果它总是需要引用一个有效的对象,则是一个引用)new
std::vector
delete myInt;
myInt = reftoMyInt = refToMyInt2 = nullptr;
weak_ptr
],因为每次使用lock()
函数访问值有点麻烦和不切实际......”——它不应该比在访问指向对象之前检查 null 更麻烦/不切实际。(与 。你确定要明确禁止作为这个问题的答案,仅仅因为你尝试使用它很麻烦吗?if (target != nullptr)
if (auto locked = target.lock())
weak_ptr