提问人:user_185051 提问时间:9/8/2020 最后编辑:user_185051 更新时间:9/8/2020 访问量:198
std::vector 在堆上分配了元素 - 我需要 5 法则吗?
std::vector with elements allocated on the heap - do I need rule of 5?
问:
如果我有一个班级,成员是这样的:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
我是否需要编写五法则函数,或者 std::vector 会负责深度复制和删除堆上分配的元素?
编辑: 下面的代码使用默认的复制构造函数,因此我假设my_class1对象复制到my_class2对象后,my_class1.my_vector 和 my_class2.my_vector 的元素将是相同的,因为复制了 MyStruct 指针,而不是数据本身。但是,输出显示它们并不相同。您可以在此处运行代码:https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
编辑2:我知道智能指针。我特别感兴趣的是,如果我使用原始指针会发生什么。
答:
2赞
Tanveer Badar
9/8/2020
#1
您需要实现复制构造函数、复制赋值和析构函数。
此外,请考虑将向量声明从
std::vector<MyStruct*> my_vector;
自
std::vector<std::unique_ptr<MyStruct>> my_vector;
这样它实际上就正确地拥有堆分配的对象。执行此更改将帮助您不编写析构函数。
评论
0赞
user_185051
9/8/2020
你能根据我对原始帖子的编辑添加更多细节吗?如果我使用例如默认复制构造函数,究竟会发生什么?
1赞
ivan.ukr
9/8/2020
#2
不,不负责指针存储的对象的深度复制。解决此问题的可能性很小:std::vector
- 按值存储。
MyStruct
- 商店。
std::unique_ptr<MyStruct>
- 商店。
std::shared_ptr<MyStruct>
请注意,由于仅包含原始类型的字段,因此不需要复制构造函数、赋值运算符和析构函数,否则您必须实现它们,因此编译器将自动生成的默认实现就足够了。MyStruct
评论
0赞
user_185051
9/9/2020
如果 不会处理深度复制,那么为什么“编译器会自动生成的默认实现就足够好了”?我假设默认实现将对矢量的元素进行浅层复制,不是吗?std::vector
1赞
ivan.ukr
9/9/2020
复制构造函数、赋值和析构函数仅在类中保持一些非平凡状态时才是必需的,例如,如果您有指向某个对象的指针,因此在从 this 或赋值创建新对象时必须复制该对象。int、double 等原始数值类型的成员变量可以逐位复制,这是编译器默认做的,所以就足够了。
评论
vector
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
my_class1. my_vector
my_class2
vector
my_class