悬空指针问题 C++

Dangling pointer issue C++

提问人:Fewnity 提问时间:6/18/2023 更新时间:6/18/2023 访问量:112

问:

我正在制作一个游戏引擎,但我遇到了破坏元素的问题。

例如,我有一些摄像机可以跟踪并观察目标(游戏对象或演员)。 在游戏的后期,相机目标被销毁,相机代码将崩溃,因为代码将尝试访问释放的对象,我想避免这种崩溃。

所以这里有一个简化的代码示例:
我有一个实例化的对象,例如一个 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,因为我可以对该对象进行数十次引用。
我找到了一个解决方案,但它是要使用的,我想避免使用它,因为每次都使用该函数访问值有点麻烦且不切实际......
nullptrrefToMyIntrefToMyInt2weak_ptrlock()

还有其他解决方案吗?谢谢!

C++ 空指针

评论

5赞 Some programmer dude 6/18/2023
delete不修改指针。
1赞 Some programmer dude 6/18/2023
除非你的示例只是你真实代码的简化(过于简化的 IMO)示例,否则不要有指向简单类型的指针。这几乎从来都没意义。我还建议你花一些时间回过头来谈谈你的需求、需求分析和设计。需求、分析和设计真的激发了指针的使用吗?
2赞 Pepijn Kramer 6/18/2023
你用得太多了。学习使用标准库容器,如 ,如果(且仅当)您确实需要手动分配内存(通常仅适用于多态类),则使用 std::make_unique。请参阅 R.11 C++ 核心指南。现在我只希望在数据结构类中看到新的/删除。我看到的任何原始指针我都希望是非拥有的(或者如果它总是需要引用一个有效的对象,则是一个引用)newstd::vector
1赞 Eljay 6/18/2023
在该行之后,添加以下行: 这应该可以解决问题。程序员有责任让这些事情井井有条。delete myInt;myInt = reftoMyInt = refToMyInt2 = nullptr;
2赞 JaMiT 6/18/2023
“我想避免使用 [weak_ptr],因为每次使用 lock() 函数访问值有点麻烦和不切实际......”——它不应该比在访问指向对象之前检查 null 更麻烦/不切实际。(与 。你确定要明确禁止作为这个问题的答案,仅仅因为你尝试使用它很麻烦吗?if (target != nullptr)if (auto locked = target.lock())weak_ptr

答:

-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())*ptrptrnullptr

if (ptr != nullptr) {
  auto value = *ptr;
}

这仅比以下情况略显冗长:

if (auto sptr = ptr.lock()) {
  auto value = *sptr;
}

答:

解决方案是 和 的组合。std::shared_ptrstd::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

我保留了原始变量名称,以便于比较。