简体   繁体   中英

C++ operator overloading return pointer

I'm fairly new to programming in C++ and I was wondering something:

whenever I see operator overloading in C++ it's done like this:

#ifndef STONE_H
#define STONE_H

class Stone {
    private:
    int weight;

    public:
    .......

    Stone operator+(const Stone& s) {
        Stone stone;
        stone.weight = this->weight + s.weight;
        return stone;
    }

    .......
}


#endif

But when the "+" operator is called, it creates an object "stone", and returns a copy of this. This can't be good for performance when dealing with huge objects?

Wouldn't it be better to use dynamic memory for this as in the example below:

Stone * operator+(const Stone& s) {
    Stone * stone = new Stone;
    stone->weight = this->weight + s.weight;
    return stone;
}

Or am I seeing this wrong?

Thanks in advance

Trying to reason things out is not particularly accurate way of estimating performance: you need to actually write a program to measure whether or not one implementation is better than another.

There are a number of ways in which no copy will happen at all; the named return value optimization (NRVO) and move assignment are relevant ideas here.

Even if you decide that you want to do something like your suggestion, you shouldn't implement it as you have, since it has the wrong semantics: you've had operator+ return a pointer-to-thing rather than a thing. Also, working with pointers (especially bare pointers) is risky, since it gives you a lot more opportunities to make mistakes.

If you want to implement something along those lines, you need to wrap the pointer semantics in a class that provides value semantics.

Turns out on the current standard, this is a bit different:

#include <iostream>

class big {
  int* v; // Demonstration purposes. A smart pointer or a standard container would be better.
  public:
  big& operator+=(big& o) {
    for (int i=0;i<1000;++i) {
      v[i] += o.v[i];
    }
    return *this;
  }

  big(int val = 0)
      :    v{new int[1000]} // We're using RAII to prevent resource leaking.
  {
    std::cout << "a construction.\n";
    for (int i=0;i<1000;++i) {
      v[i] = val;
    }
  }

  // Copy constructor
  big(big& o) 
      :    v{new int[1000]}
  {
    std::cout << "a copy construction.\n";
    for (int i=0;i<1000;++i) {
      v[i] = o.v[i];
    }
  }

  // Move assignment
  big& operator=(big&& o) {
    std::cout << "a move assignment.\n";
    if (v) delete[] v;
    v = o.v;
    o.v = nullptr;
  }

  // Move constructor
  big (big&& o) {
    std::cout << "a move construction.\n";
    v = o.v;
    o.v = nullptr;
  }

  ~big() {
    if (v) delete[] v;
  }
};

// a will be move-constructed if using a temporary, or copy-contructed if not.
// The result will always be passed by a cheap move
big operator+(big a, big& b) {
  return std::move(a += b);
}

int main() {
  big a{1};
  big b{2};
  big c{3};

  big d = a+b+c;
}

Output: (with comments added)

a construction. // Constructed a
a construction. // Constructed b
a construction. // Constructed c
a copy construction. // a+b <- a copied into parameter "a" of operator+. b is passed by reference.
a move construction. // The temporary from the operation above, moved into parameter "a" of operator+. c is passed by reference.
a move construction. // d is move constructed from the temporary generated by a+b+c.

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