对象指针和超出范围的对象的矢量
Vector of object pointers and objects going out of scope
我正在使用一个派生类和指向该类中对象的指针向量。我在实现复制构造函数等方面遇到了一些问题,即使在读了很多关于它的文章之后也是如此。我使用的是c++11。
我有一个循环,在其中创建派生类的新对象,然后我想将这些对象放入向量中。但由于它是一个指针向量,我必须将创建对象的地址放在那里。
我相信我的问题源于这个事实,再加上对象超出范围等,以及我无法以令人满意的方式实现复制构造函数/复制赋值构造函数等。
我举了一个很小的例子来说明我的问题。假设初始设置如下(我知道这没有多大意义,例如使用指针*n
,但我认为这表明了我实际代码的问题):
using namespace std;
#include <iostream>
#include <vector>
class Base {
protected:
int* n;
public:
void display(string name="") {cout << name << "n = " << *n << endl;}
Base() {}
Base(int n_) {
*n=n_;
cout << "Initialised to " << *n << endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {}
Derived(int n_) : Base(n_) {}
};
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
Derived tmp(i);
tmp.display("Tmp: ");
list.push_back(&tmp);
}
cout << endl;
for(int i=0;i<list.size();i++) {
cout << "Address of " << i << ": " << list[i] << endl;
list[i]->display("Element "+to_string(i)+" : ");
}
}
其输出为:
Initialised to 0
Tmp: n = 0
Initialised to 1
Tmp: n = 1
Initialised to 2
Tmp: n = 2
Initialised to 3
Tmp: n = 3
Initialised to 4
Tmp: n = 4
Address of 0: 0x7fff3a1df2d0
Element 0 : n = 0
Address of 1: 0x7fff3a1df2d0
Element 1 : n = 0
Address of 2: 0x7fff3a1df2d0
Element 2 : n = 0
Address of 3: 0x7fff3a1df2d0
Element 3 : n = 0
Address of 4: 0x7fff3a1df2d0
Element 4 : n = 0
因此,在循环之后,列表中的所有元素都指向同一地址,其中n=0(可能是tmp
超出范围的未定义行为)。
因此,与其只是将tmp
的地址放入list
,我想我必须以某种方式使Derived
的实例在循环中幸存下来,同时仍然只有list
中的地址。
如前所述,我尝试过使用各种特殊的成员函数来实现这一点,但没有成功。
请注意,实现对象向量本身似乎更容易,但这会在我的实际代码中导致其他问题。如果我不能做到这一点,我会试试看。
它与复制或复制构造函数无关,只是因为对象超出了范围并被销毁,而您仍然保留一个指向这些(现在已销毁)对象的指针。当您试图取消引用这些指针时,这会导致未定义的行为。
相反,您需要动态地分配这些对象,例如使用new
。您可以使用C++11智能指针包装这些指针。
将指向堆栈上对象的指针添加到向量中。当当前作用域结束时,这些对象将被销毁,但指针仍在那里。
您将不得不创建新对象。
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
auto tmp = new Derived{i};
tmp->display("Tmp: ");
list.push_back(tmp);
}
// ...
}
}
现在,您仍然需要确保根据需要释放对象。只要可能,首选unique_ptr<>
或shared_ptr<>
:
int main(int argc, const char* argv[]) {
vector<unique_ptr<Base>> list;
for(int i=0;i<5;i++) {
auto tmp = make_unique<Derived>(i);
tmp->display("Tmp: ");
// this should move the unique_ptr and therefore transfer
// its ownership to the vector.
list.emplace_back(tmp);
}
// ...
}
}
现在,对象将被销毁,无论是从向量中移除对象,还是在向量被销毁时。对于可能被延迟的shared_ptr,直到程序的任何部分都没有将任何shared_ptr<>
保存到同一对象。
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 超出范围时使用对象
- 如何访问超出其块范围的对象?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- C++:返回一个基于范围 for 循环迭代器,其中包含继承对象
- 对象超出范围/转让所有权
- 从函数返回范围视图时,带有std::span:中间对象所有权的C++Ranges-v3
- 读取互斥对象范围之外的volatile变量,而不是std::atomic
- 是否可以在C++ (C) 中使用全局范围对象(结构)?
- 基于范围的 for 循环将对象移动到另一个容器中?
- 对象超出范围后,引用成员设置为 0
- 哪个函数负责C++全局范围内的类对象初始化?
- 非常量对象的向量似乎在基于范围的 for 循环中被视为常量
- 如果一个对象是在本地创建的,并在C++中作为异常抛出,那么本地对象如何在其范围之外有效,即在 catch 块中?
- 什么是OOP中的对象范围
- 在C++中,指向对象的指针将指向对象范围之外的内容
- 抛出的对象范围
- C++:在对象范围外调用析构函数
- 如何根据多个参数查找容器中的对象范围
- 将对象范围扩展到if语句之外