如何在c++中减少拷贝

How to reduce copy in c++

本文关键字:拷贝 c++      更新时间:2023-10-16

我正在编写一个Bytearray类,并希望实现一个成员函数copy(int start, int end),它可以复制一段数据并返回一个新的Bytearray对象。我的实现是

Bytearray Bytearray::copy(int start, int end){
    Bytearray b(end - start);
    for(int i = start; i < end; i++){
        b._data[i-start] = _data[i];
    }
    return b;
}

但是,据我所知,如果我调用Bytearray aa = bb.copy(1, 5);,它需要3次复制数据。一种是将数据从this复制到临时对象b。然后调用复制构造函数和operator =。如何减少副本,提高效率。

您的函数根本不调用Bytearray::operator=()。调用方可以在表达式x = a.copy(start, end)中。

在实践中,大多数现代编译器将省略临时变量,尽管严格来说,标准并不要求它们这样做。

在c++ 11中,您可以提供一个move构造函数,它将更明确地鼓励编译器省略临时变量。如果没有这个(例如,你没有在c++ 11中提供移动构造函数,或者你使用的是c++ 11之前的编译器),典型的方法是通过引用

传递目标对象。
void Bytearray::copy(int start, int end, Bytearray& b)
{
   for(int i = start; i < end; i++){
      b._data[i-start] = _data[i];
}

或指针

void Bytearray::copy(int start, int end, Bytearray* b)
{
    // assume b is the address of a valid object
    for(int i = start; i < end; i++){
        b->_data[i-start] = _data[i];
}

应该实现move构造函数和move赋值。它将允许编译器移动数据而不是复制数据。它基本上是这样的:

Bytearray Bytearray::copy(size_t start, size_t end) {
    Bytearray b; // declare as usual
    return move(b); // the return value is constructed by move
}
// how to use it?
// use it as usual!
// myB is constructed by move.
Bytearray myB = otherB.copy();

如何实现?这很简单。它类似于复制构造函数,但你窃取数据而不是复制数据。

struct Bytearray {
    Data* _data = nullptr; // null by default
    // _data should be a unique_ptr and declared like this : 
    // unique_ptr<Data> _data;
    // unique_ptr works with array too.

    // move constructor
    Bytearray (Bytearray&& other) {
        // we have the other's data, the other becomes null.
        swap(_data, other._data);
    }
    // move assignation
    Bytearray& operator=(Bytearray&& other) {
        // same thing here, we swap the data.
        swap(_data, other._data);
        // as we swap, we get the new data. 
        // Since other is temporary, our old data is deleted by other destructor.
        // No leak here.
    }
        // you could mark copy constructor and copy assignation as deleted here.
};

给你!不再复制,不再有指针和引用

下面是一种典型的方法:

void Bytearray::copy(int start, int end, Bytearray* b){
  for(int i = start; i < end; i++){
    b->_data[i-start] = _data[i];
  }
}
...
Bytearray aa(4);
bb.copy(1, 5, &aa);