yewei
yewei

Reputation: 241

c++ however to avoid deep copy issue

for the below code demo, I send a reference into a class, and add some items to the vector, then return the vector, I think there is copy issue in the assignment test = a.return_data() in the main function, is there some method to improve the efficiency?

#include <iostream>
#include <stdio.h>
#include <vector>

using namespace std;

class A 
{
public:
    A(vector<int> &a);
    void additem(int c);
    vector<int> return_data();
private:
    vector<int> d;
};

A::A(vector<int> &a)
  {
      d = a;
  }

void A::additem(int c)
{
      d.push_back(c);
}

vector<int> A::return_data()
{
    return d;
}

void main()
{
    vector<int> test;

    for(int i=0; i<10; i++)
    {
        test.push_back(i);
    }
    cout << test.size() << endl;
    A a(test);
    a.additem(10);
    test = a.return_data();
    cout << test.size() << endl;
}

Upvotes: 1

Views: 178

Answers (3)

songyuanyao
songyuanyao

Reputation: 172934

You could hold a reference member in the class,

class A 
{
... ...
private:
    vector<int>& d;
};

And then use member initializer lists to initialize it in ctor,

A::A(vector<int> &a) : d(a) {}

And then no need to use return_data() anymore,

void main()
{
    vector<int> test;

    for(int i=0; i<10; i++)
    {
        test.push_back(i);
    }
    cout << test.size() << endl;
    A a(test);
    a.additem(10);
    // test = a.return_data();
    cout << test.size() << endl;
}

LIVE

NOTE: Make sure the reference will not be invalid.

Upvotes: 3

Marco A.
Marco A.

Reputation: 43662

If you don't need your class to exclusively own the vector you might simply get away with a reference (and render return_data obsolete)

class A {
public:
  A(vector<int> &a);
  void additem(int c);
private:
  vector<int>& d; // Just store a reference
};

A::A(vector<int> &a) : d(a) {}

int main() {
  vector<int> test;

  for (int i = 0; i<10; i++) {
    test.push_back(i);
  }
  cout << test.size() << endl;
  A a(test);
  a.additem(10);
  cout << test.size() << endl;
}

Live Example

Anyway, if you do need to deal with ownership (following the rule of zero) you could use unique_ptrs and move them around

class A {
public:
  A(unique_ptr<vector<int>>&& a);
  void additem(int c);
  unique_ptr<vector<int>> return_data();
private:
  unique_ptr<vector<int>> d; // Unique owner of the vector
};

A::A(unique_ptr<vector<int>>&& a) : 
  d(forward<unique_ptr<vector<int>>>(a))
{}

unique_ptr<vector<int>> A::return_data() {
  return move(d); // Moves the member vector (can no longer be used)
}

int main() {
  unique_ptr<vector<int>> test = make_unique<vector<int>>();;

  for (int i = 0; i<10; i++) {
    test->push_back(i);
  }
  cout << test->size() << endl;
  A a(move(test));
  a.additem(10);
  test = a.return_data();
  cout << test->size() << endl;
}

Live Example

In both cases no copies are necessary and thus even for large vectors it should prove to be faster than your approach. Keep in mind that the latter approach is one-shot-only, i.e. you don't get to return multiple copies of the vector.

Upvotes: 1

Blacktempel
Blacktempel

Reputation: 3995

Instead of return_data you could simply let the user of the function pass an argument, which you will take by reference.

void get_data(std::vector<int> &vec)
{
    //Now you can either copy or move
    vec = d;
    //or
    vec = std::move(d);
}

You cannot always be sure, that the element of the reference being hold in the class still exists later.

Upvotes: 0

Related Questions