提问人:roy.atlas 提问时间:6/22/2022 更新时间:6/23/2022 访问量:188
在C++中,如何正确获取指向向量的共享指针,最大限度地减少复制构造函数调用的次数?
In C++, how to correctly obtain a shared pointer to a vector , minimizing the number of copy constructor calling?
问:
我需要一个函数,该函数将shared_ptr返回到包含大量对象的向量。下面的代码实现了这一点,但可以看到复制构造函数被调用了额外的次数。
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class A {
public:
int IA ;
A(int ia) {
cout << "Constructor is called\n" ;
IA = ia ;
}
A(const A& a) {
cout << "Copy constructor is called\n" ;
IA = a.IA ;
}
} ;
shared_ptr<vector<A>> foo() {
vector<A> myA ;
myA.push_back(A(10)) ;
myA.push_back(A(20)) ;
return make_shared<vector<A>>(myA) ;
}
int main() {
shared_ptr<vector<A>> myA ;
myA = foo() ;
return 0 ;
}
在实际情况下,A 也可能更大,因此会导致不必要的复制过程。我想知道是否有任何方法可以减少复制构造函数调用时间。make_shared<vector<A>>(myA) ;
答:
这条线
return make_shared<vector<A>>(myA) ;
正在制作不必要的副本。您无需先创建向量,然后将其复制到另一个动态分配的向量。您只需要创建一个向量:
shared_ptr<vector<A>> foo() {
return make_shared<vector<A>>(std::initializer_list<A>{{10},{20}});
}
谢谢!现在的代码是:
shared_ptr<vector<A>> foo2() {
auto ptr = make_shared<vector<A>>() ;
(*ptr).reserve(99) ;
ptr->emplace_back(A(10)) ;
ptr->emplace_back(A(20)) ;
return ptr ;
}
int main() {
shared_ptr<vector<A>> myA, myA2 ;
myA2 = foo2() ;
cout << (*myA2)[0].IA << endl;
return 0 ;
}
复制构造函数调用的次数减少到两个。是否可以继续避免调用复制构造函数,因为我认为没有理由在构造后制作副本。
评论
代码中有两种用法会导致额外的复制。
myA.push_back(A(10))
将创建一个 class 的临时对象,然后将其复制到 vector 中。请注意,我们不能通过更改为 来减少这种重复。它还将创建一个临时对象,然后使用临时 (xvalue) 作为参数调用构造函数。这将调用复制构造函数(因为您没有提供移动构造函数)。A
myA
myA.emplace_back(A(10))
A
A
make_shared<vector<A>>(myA)
将在 from 中创建托管对象,该对象将被复制。复制向量将复制其所有元素。std::shared_ptr
myA
解决 方案:
提供适当的 arugment to .在这里我们可以写.现在它将调用 with argument 的构造函数,它将选择构造函数。也就是说,直接在向量中构造类的对象,而不是创建一个临时的,然后将其复制到向量中。
emplace_back
myA.emplace_back(10)
A
10
A(int)
A
进入 by .在这里,它不会复制向量中的元素。
myA
shared_ptr
make_shared<vector<A>>(std::move(myA))
请注意,随着向量容量的增加,其元素也将被复制。有一些解决方案。如果您知道元素的数量,则可以使用来预分配足够的内存。您还可以为类预置一个 noexcept 移动构造函数,以避免在更改容量时复制。reserve()
A
上一个:运算符重载影响我的复制构造函数
评论
std::make_shared<vector<A>>(std::move(myA));
vector
std::make_shared
return make_shared<vector<A>>(std::move(myA));
make_shared
从其参数中创建一个具有共享所有权的新对象。如果您不想要副本,请不要先制作原件。您不能获取现有对象并“使其共享”。