简体   繁体   English

在 C++ 中,如何正确获取指向向量的共享指针,最大限度地减少复制构造函数调用的次数?

[英]In C++, how to correctly obtain a shared pointer to a vector , minimizing the number of copy constructor calling?

I need a function which returns a shared_ptr to a vector containing a large number of objects.我需要一个将 shared_ptr 返回到包含大量对象的向量的函数。 The following code realizes this but one can see that copy constructors are called for an extra number of times.下面的代码实现了这一点,但可以看到复制构造函数被调用了多次。

#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 ;
}

In real cases, A may also be bigger, so to make_shared<vector<A>>(myA) ;在实际情况下,A 也可能更大,所以要make_shared<vector<A>>(myA) ; would cause unncessary copying process.会导致不必要的复制过程。 I wonder if there is any way to reduce copy constructor calling times.我想知道是否有任何方法可以减少复制构造函数的调用时间。

This line这条线

return make_shared<vector<A>>(myA) ; 

Is making an unnecessary copy.正在制作不必要的副本。 You do not need to create a vector first then copy it to another dynamically allocated vector.您无需先创建向量,然后将其复制到另一个动态分配的向量。 You only need to create one vector:您只需要创建一个向量:

shared_ptr<vector<A>> foo() {
    return make_shared<vector<A>>(std::initializer_list<A>{{10},{20}}); 
}

Thanks!谢谢! The code now is :现在的代码是:

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 ;
}

The number of copy constructor calling is reduced to two.复制构造函数调用的数量减少到两个。 Is it possible to continue to avoid calling the copy constructor at all, for I see no reason to make a copy after construction.是否可以继续避免调用复制构造函数,因为我认为没有理由在构造后进行复制。

There are two usages in your code that cause extra copying.您的代码中有两种用法会导致额外的复制。

  1. myA.push_back(A(10)) will create a temporary object of class A , which is then copied into the vector myA . myA.push_back(A(10))将创建一个类A的临时对象,然后将其复制到向量myA中。 Note that we cannot reduce such duplication by changing to myA.emplace_back(A(10)) .请注意,我们无法通过更改为myA.emplace_back(A(10))来减少此类重复。 It will also creates a temporary A object, and then calls the constructor of A with the temporary (xvalue) as an argument.它还将创建一个临时A对象,然后以临时 (xvalue) 作为参数调用A的构造函数。 This will call the copy constructor (since you didn't provide move constructor).这将调用复制构造函数(因为您没有提供移动构造函数)。

  2. make_shared<vector<A>>(myA) will create the managed object in std::shared_ptr from myA , which will be copied. make_shared<vector<A>>(myA)将在std::shared_ptrmyA创建托管对象,该对象将被复制。 Copying a vector will copy all of its elements.复制向量将复制其所有元素。

Solutions:解决方案:

  1. Provide appropriate arugment to emplace_back .emplace_back提供适当的参数。 Here we can write myA.emplace_back(10) .在这里我们可以写myA.emplace_back(10) Now it will call the constructor of A with argument 10 , which will select the constructor A(int) .现在它将使用参数10调用A的构造函数,这将选择构造函数A(int) That is, construct the object of class A directly in the vector, instead of creating a temporary and then copying it into the vector.即直接在vector中构造A类的对象,而不是先创建一个临时的,然后再复制到vector中。

  2. Move myA into the shared_ptr by make_shared<vector<A>>(std::move(myA)) .通过make_shared<vector<A>>(std::move(myA))myA移动到shared_ptr中。 Here it will not copy the elements in the vector.这里它不会复制向量中的元素。

Note that as the capacity of the vector increases, its elements will also be copied.请注意,随着向量容量的增加,它的元素也将被复制。 There are some solutions.有一些解决方案。 If you know the number of elements, you can use reserve() to pre-allocate enough memory.如果您知道元素的数量,则可以使用reserve()来预先分配足够的内存。 You can also previde a noexcept move constructor for class A to avoid copying when changing the capacity.您还可以为类A提供一个 noexcept 移动构造函数,以避免在更改容量时复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM