为啥在删除引用指向它的对象后继续存在?

Posted

技术标签:

【中文标题】为啥在删除引用指向它的对象后继续存在?【英文标题】:Why after deleting object which reference points to it continues to live?为什么在删除引用指向它的对象后继续存在? 【发布时间】:2018-10-29 11:00:34 【问题描述】:

我有这样的程序:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class no_object : public std::exception

    protected:
        std::string mMsg;
    public:
        no_object(const char* msg) : mMsg(msg) 
        virtual ~no_object() noexcept override 
        virtual const char* what() const noexcept override  return mMsg.c_str(); 
;

using namespace std;

class Object 
public:
    Object(const string info) : information(info)  cout << "Object constructor!" << endl; 
    ~Object()  cout << "Object destructor!" << endl; 
    Object(const Object& obj)  information = obj.information; cout << "Copy constructor!" << endl; 
    void setInformation()   
    string getInformation() const  return information; 
private:
    string information;
;

class Storage 
public:
    Storage(const size_t width) 
        objs = static_cast<Object*>(malloc(sizeof(Object) * width));

        if (objs == NULL)
            throw std::bad_alloc();

        lastPointer = objs + sizeof (Object) * (width - 1);
    

    void storeObject(Object& obj, size_t index) 
        if (isIndexOutOfRange(index))
            throw std::out_of_range("Oops, index is out of range!");

        availableIndexes.push_back(index);
        objs[index] = obj;
    

    Object& getObjectAtIndex(size_t index) const 
        if (isIndexOutOfRange(index))
            throw std::out_of_range("Oops, index is out of range!");

        auto it = find(availableIndexes.begin(), availableIndexes.end(), index);
        if (it == availableIndexes.end())
            throw no_object("Oops, the object for this index is not set!");

        return objs[index];
    

    ~Storage() 
        free(objs);
    
private:
    bool isIndexOutOfRange(size_t index) const noexcept 
        Object* indexPointer = objs + sizeof (Object) * index;

        if (indexPointer > lastPointer)
            return true;

        return false;
    

    vector<size_t> availableIndexes;

    Object* objs;
    Object* lastPointer;
;

int main()

    Storage storage(3);
    
        cout << "1" << endl;
        Object obj = Object("lambo");
        cout << "2" << endl;
        Object& objRef = obj;
        cout << "3" << endl;
        storage.storeObject(objRef, 2);
    

    cout << "4" << endl;
    Object savedObject = storage.getObjectAtIndex(2);
    cout << "Information from stored object is " << savedObject.getInformation() << endl;

    return 0;

有趣的是我有下一个输出:

1
Object constructor!
2
3
Object destructor!
4
Copy constructor!
Information from stored object is lambo
Object destructor!

该程序存储对对象的引用,然后我们可以获取它们。据我所知,在删除引用指向的对象后,引用变得不可用并且它指向垃圾。

这是我的问题: 1. 我可以这样使用引用吗?安全吗? 2. 为什么要调用拷贝构造函数? 3. 我的代码是否存在其他问题? 4. 如何修正这个程序是正确的?

提前致谢。

【问题讨论】:

删除后,它在“踢足球时不允许使用双手”的意义上确实变得不可用。踢球的时候手还是可以用的,就是违反规则 下次请尝试提供MCVE。 storeObjectgetObjectAtIndexgetObjectAtIndex 之类的东西根本与问题无关。请省略任何分散实际问题的内容 这会导致未定义的行为,这意味着任何事情都可能发生。您对行为的期望不正确 @Oleg 您确实需要在复制分配给它们之前创建这些对象(不是真的,这只是未定义的行为)。请参阅 user2079303 的答案。如果你想坚持使用malloc,你至少应该在复制分配之前使用一个placement-new。您也可以查看std::aligned_storage 而不是malloc “他没死,法官大人!他就在那儿,我可以戳他,他还有衣服、钱包和所有东西,所以他一定还活着。” 【参考方案1】:

这个程序存储对对象的引用,然后我们可以得到它们

它不存储引用。它存储对象。

    我可以这样使用参考吗?安全吗?

在程序中使用引用的方式是安全的。您的任何引用都不会比被引用对象的生命周期长。

    为什么要调用复制构造函数?

因为Object savedObject = storage.getObjectAtIndex(2);是拷贝初始化。

    我的代码中是否存在其他问题?

您使用malloc 分配了一块内存,而没有在内存中构造任何Object 实例。然后在objs[index] = obj; 行上,您复制分配内存中的Object 实例......除了没有Object 实例,因为您从未构造过任何实例。因此,您的程序的行为是未定义的。

另外,Storage 是不安全的,因为如果您复制它(意外或故意),它将尝试释放相同的分配两次。其行为将是未定义的。

要解决这两个问题,请使用 std::vector 而不是尝试手动内存管理。

另外,lastPointer = objs + sizeof (Object) * (width - 1); 超出了分配内存的范围。您可能忽略了指针算术通过对象大小的增量起作用的事实。在这种情况下,进一步乘以 sizeof (Object) 毫无意义。

【讨论】:

但是 Object obj = 呢?据我了解,它超出了范围,并且参考无效。 @Oleg 目前不存在对obj 的引用。

以上是关于为啥在删除引用指向它的对象后继续存在?的主要内容,如果未能解决你的问题,请参考以下文章

第15章 对象和数组

即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?

消除过期的对象引用

从数组和引用指针中删除后释放

浅谈垃圾回收机制

引用还是指针?