悬空指针问题C++

h4cxqtbf  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(116)

我正在做一个游戏引擎,我遇到了一个破坏元素的问题。
例如,我有一些摄像机跟随并观察目标(游戏对象或演员)。在游戏的后期,摄像机目标被破坏,摄像机代码将崩溃,因为代码将尝试访问一个释放的对象,我想避免这种崩溃。
下面是一个简单的代码示例:
我有一个示例化的对象,例如一个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
我不想手动将refToMyIntrefToMyInt2设置为nullptr,因为我可能有几十个对该对象的引用。
我已经找到了一个解决方案,但它是使用weak_ptr,我想避免使用它,因为每次使用lock()函数访问值有点麻烦和不切实际...
有别的解决办法吗?谢谢你!

kokeuurv

kokeuurv1#

**“我想避免使用它,因为每次使用lock()函数访问值有点麻烦和不切实际。

对于*(ptr.lock())*ptr,这可能是正确的,但这是一个错误的比较。在解引用ptr之前,您应该始终检查ptr是否是nullptr

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

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

l5tcr1uw

l5tcr1uw2#

下面的例子将向您展示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;
}

相关问题