为什么删除引用后的对象仍然存在?

时间:2018-10-29 11:00:34

标签: c++ c++11 exception reference stl

我有这样的程序:

#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.如何正确纠正此程序?

谢谢。

1 个答案:

答案 0 :(得分:2)

  

该程序存储对对象的引用,然后我们可以获取它们

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

  
      
  1. 我可以通过这种方式使用参考吗?安全吗?
  2.   

在程序中使用引用的方式很安全。您的引用中没有一个存在超过被引用对象的生存期。

  
      
  1. 为什么要调用拷贝构造函数?
  2.   

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

  
      
  1. 我的代码中是否还有其他问题?
  2.   

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

此外,Storage是不安全的,因为如果您(无意或有意地)为其复制副本,它将尝试释放两次相同的分配。其行为将是不确定的。

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

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