简体   繁体   中英

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. 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) ; 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 . Note that we cannot reduce such duplication by changing to 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. 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. Copying a vector will copy all of its elements.

Solutions:

  1. Provide appropriate arugment to emplace_back . Here we can write myA.emplace_back(10) . Now it will call the constructor of A with argument 10 , which will select the constructor 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.

  2. Move myA into the shared_ptr by make_shared<vector<A>>(std::move(myA)) . 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. You can also previde a noexcept move constructor for class A to avoid copying when changing the capacity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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