Zhuoran He
Zhuoran He

Reputation: 973

Is it possible to do a swap on return in c++, instead of return by value?

Suppose I'm coding a string class in C++ (I know I can use the library). The string length is variable and the storage space is dynamically allocated in the constructor and freed in the destructor. When the main function calls c=a+b (a,b,c are strings), the operator+ member function creates a temporary object that stores the concatenated string a+b, returns it to the main function, and then the operator= member function is called to free the string originally stored in c and copy data from the temporary string a+b to c, and finally the temporary a+b is destructed.

I'm wondering if there's a way to make this happen: instead of having the operator= copy data from a+b to c, I want it to swap the data pointers of a+b and c, so that when a+b is destructed, it destructs the original data in c (which is what we want), while c now takes the result of a+b without needing to copy.

I know coding a 2-parameter member function setToStrcat and calling c.setToStrcat(a,b) can do this. For example, the function can be coded as:

    void String::setToStrcat(const String& a,const String& b){
      String tmp(a.len+b.len); int i,j;
      for(i=0;i<a.len;i++) tmp[i]=a[i];
      for(j=0;j<b.len;i++,j++) tmp[i]=b[j];
      tmp[i]='\0'; this->swap(tmp);
    }

    void String::swap(String& a){
      int n=len; len=a.len; a.len=n;
      char *s=str; str=a.str; a.str=s;
    }

I omitted the definitions of my constructor (which allocates len+1 char-type spaces) and operator[] (which returns a reference of the ith character). The swap function swaps the data pointers and length variables between *this and tmp, so that when tmp is destructed after the swap, it is actually the data originally stored in *this (the String c in the main function) that is destructed. What *this now has in its possession (c.str) is the concatenated string a+b.

I would like to know if there is a way to optimize the performance of c=a+b to the same level. I tried c.swap(a+b) and changed the return type of a+b to String&, but I receive warning (reference to a local variable) and GDB shows that the temporary gets destructed before the swap happens, while I want the other way.

I think my question is general. In C++ programming, we often need a temporary object to store the result of a function, but when we assign it to another object in the main function, can we not copy the data but use a (much faster) swap of pointers instead? What is a neat way of making this happen?

Upvotes: 4

Views: 747

Answers (1)

Krzysztof Kosiński
Krzysztof Kosiński

Reputation: 4325

In C++11, you can do this by writing a move constructor. Rvalue references were added to the language to solve this exact problem.

class String {
  ...
  String(String&& s) : str(nullptr) {
    this->swap(s);
  }
  String& operator=(String&& s) {
    this->swap(s);
  }
  ...
  String operator+(String const& other) {
    // (your implementation of concatenation here)
  }
  ...
}

Then code like this will not trigger an extra copy constructor or a memory allocation, it will just move the allocated memory from the temporary (the thing returned from operator+) to the new object c.

String c = a + b;

Upvotes: 1

Related Questions