C++ 运算符重载 return 指针
C++ operator overloading return pointer
我对 C++ 编程还很陌生,我想知道一些事情:
每当我在 C++ 中看到运算符重载时,它都是这样完成的:
#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
但是当调用“+”运算符时,它会创建一个对象 "stone",并且 returns 是它的一个副本。这在处理大对象时对性能不利吗?
像下面的例子那样使用动态内存不是更好吗:
Stone * operator+(const Stone& s) {
Stone * stone = new Stone;
stone->weight = this->weight + s.weight;
return stone;
}
还是我看错了?
提前致谢
尝试推理并不是评估性能的特别准确的方法:您需要实际编写一个程序来衡量一种实现是否优于另一种实现。
有多种方法可以完全避免复制;命名的 return 值优化 (NRVO) 和移动分配是这里的相关想法。
即使您决定要按照您的建议做某事,您也不应按原样实施,因为它的语义错误:您已经 operator+
return指向事物而不是事物的指针。此外,使用指针(尤其是裸指针)是有风险的,因为它给了你更多犯错的机会。
如果你想按照这些思路实现某些东西,你需要将指针语义包装在提供值语义的 class 中。
原来在现在的标准上,这个有点不一样:
#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;
}
输出:(添加了注释)
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.
我对 C++ 编程还很陌生,我想知道一些事情:
每当我在 C++ 中看到运算符重载时,它都是这样完成的:
#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
但是当调用“+”运算符时,它会创建一个对象 "stone",并且 returns 是它的一个副本。这在处理大对象时对性能不利吗?
像下面的例子那样使用动态内存不是更好吗:
Stone * operator+(const Stone& s) {
Stone * stone = new Stone;
stone->weight = this->weight + s.weight;
return stone;
}
还是我看错了?
提前致谢
尝试推理并不是评估性能的特别准确的方法:您需要实际编写一个程序来衡量一种实现是否优于另一种实现。
有多种方法可以完全避免复制;命名的 return 值优化 (NRVO) 和移动分配是这里的相关想法。
即使您决定要按照您的建议做某事,您也不应按原样实施,因为它的语义错误:您已经 operator+
return指向事物而不是事物的指针。此外,使用指针(尤其是裸指针)是有风险的,因为它给了你更多犯错的机会。
如果你想按照这些思路实现某些东西,你需要将指针语义包装在提供值语义的 class 中。
原来在现在的标准上,这个有点不一样:
#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;
}
输出:(添加了注释)
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.