Search code examples
c++vectorstructcopyshared-ptr

Avoid c++ vector copy


I want to avoid making copies of a vector that is quite large. Here is a pretty clear example of what the issue is:

struct MyStruct {
    std::vector<int> v;
    int x;
}

class MyClass {
    MyStruct lastStruct_;
public:
    MyStruct create_struct() {
        MyStruct s = { std::vector<int>(1000000, 1), 1234 };
        lastStruct_ = s;  // THIS IS A FULL COPY, PROBLEM
        return s; // THIS SHOULD NOT BE A COPY AS PER C++11 AND UP
    }
    MyStruct getLastStruct() {
            return lastStruct_;
    }
}

void main()
{
    MyClass c;
  for (int i = 0; i < A_LOT; i++)
  {
    writeToDisk(c.create_struct());
  }
  //MEANWHILE IN OTHER THREAD:
  // while(true)
  //   updateUI(c.getLastStruct());
}

How can I avoid making copies here ? I am trying to solve this with shared pointers but I am still new to these. Would something like this work (syntax might be off)?

struct MyStruct {
    std::vector<int> v;
    int x;
}

class MyClass {
    std::shared_ptr<MyStruct> lastStruct_;
public:
    MyStruct create_struct() {
        auto s = std::maked_shared<MyStruct>({ std::vector<int>(1000000, 1), 1234 });
        lastStruct_ = s;
        return *s; 
    }
    std::shared_prt<MyStruct> getLastStruct() {
            return lastStruct_;
    }
}

void main()
{
    MyClass c;
  for (int i = 0; i < A_LOT; i++)
  {
    writeToDisk(c.create_struct());
  }
  //MEANWHILE IN OTHER THREAD:
  // while(true)
  //   updateUI(c.getLastStruct()->data());
}

Solution

  • Here's the most obvious way:

    struct MyStruct {
        std::vector<int> v;
        int x;
    }
    
    class MyClass {
        std::shared_ptr<MyStruct> lastStruct_;
    public:
        std::shared_ptr<const MyStruct> create_struct() {
            auto s = std::maked_shared<MyStruct>({ std::vector<int>(1000000, 1), 1234 });
            // acquire lock
            lastStruct_ = s;
            // release lock
            return s; 
        }
        std::shared_ptr<const MyStruct> getLastStruct() {
            // acquire lock
            auto j = lastStruct_;
            // release lock
            return j;
        }
    }
    
    void main()
    {
      MyClass c;
      for (int i = 0; i < A_LOT; i++)
      {
        auto j = c.create_struct();
        writeToDisk(*j);
      }
      //MEANWHILE IN OTHER THREAD:
      // while(true)
      // {
      //   auto j = c.getLastStruct();
      //   updateUI(j->data());
      // }
    }
    

    Notice that we replace the object by replacing a shared pointer to the old object with a shared pointer to the new object. The code that's accessing the old object keeps it alive until it's done with it.

    You need some kind of lock to protect lastStruct_ from being modified in one thread while it's accessed in another thread.