新的移动构造函数/移动运算符允许我们转移对象的所有权,这样就避免了使用(昂贵的)复制构造函数调用。但是有没有可能避免构造临时对象(不使用返回参数)?
示例:在下面的代码中,构造函数被调用了4次-但理想情况下,我想要做的是避免在cross方法中构造任何对象。使用返回参数(例如void cross(const Vec3 &b, Vec3& out) )是可能的,但读起来很难看。我对更新现有变量很感兴趣。
#include <iostream>
using namespace std;
class Vec3{
public:
Vec3(){
static int count = 0;
id = count++;
p = new float[3];
cout << "Constructor call "<<id <<" "<<p<< " "<<this<< endl;
}
~Vec3(){
cout << "Deconstructor call "<<id << " "<<p<<" "<<this<< endl;
delete[] p;
}
Vec3(Vec3&& other)
: p(nullptr) {
cout << "Move constructor call "<<id << " "<<p<<" "<<this<< endl;
p = other.p;
other.p = nullptr;
}
Vec3& operator=(Vec3&& other) {
cout << "Move assignment operator call from "<<other.id<<" to "<<id << " "<<p<<" "<<this<< endl;
if (this != &other) {
p = other.p;
other.p = nullptr;
}
return *this;
}
Vec3 cross(const Vec3 &b){
float ax = p[0], ay = p[1], az = p[2],
bx = b.p[0], by = b.p[1], bz = b.p[2];
Vec3 res;
res.p[0] = ay * bz - az * by;
res.p[1] = az * bx - ax * bz;
res.p[2] = ax * by - ay * bx;
return res;
}
float *p;
int id;
};
int main(int argc, const char * argv[])
{
Vec3 a,b,c;
a = b.cross(c);
return 0;
}发布于 2013-06-26 19:54:04
另一种解决方案是从a.cross(b)返回一个“表达式对象”,将计算推迟到这样的对象被分配给c,然后在operator=中实际执行计算:
struct Vec3
{
CrossProduct cross(const Vec3& b);
Vec3& operator=(CrossProduct cp)
{
do calculation here putting result in `*this`
}
}并添加类似的构造机制等等。
这比较复杂,但许多C++数学库都使用这种设计模式。
发布于 2013-06-26 19:25:48
如果您直接分配新值:
Vec3 a = b.cross(c);那么RVO就有可能会生效,并且不会有临时的构造和移动。确保您正在使用优化进行编译。返回值将被就地构造为。
另外,在堆上分配3个浮点数的数组似乎是一个性能杀手。使用类似C的数组float p[3]或std::array<float, 3>应该会执行得更好。
发布于 2013-06-26 19:31:21
要更新现有变量,可以使用out参数:
// out parameter version
void cross(const Vec3 &b, Vec3& res){
float ax = p[0], ay = p[1], az = p[2],
bx = b.p[0], by = b.p[1], bz = b.p[2];
res.p[0] = ay * bz - az * by;
res.p[1] = az * bx - ax * bz;
res.p[2] = ax * by - ay * bx;
return res;
}当返回值用作初始值设定项(,但不是赋值给现有对象version时)时,RVO将省略构造函数:
// return value version (RVO)
Vec3 cross(const Vec3& b)
{
Vec3 t; cross(b, t); return t;
}您还可以提供result对象的赋值函数:
// assignment version
void set_cross(const Vec3& a, const Vec3& b)
{
a.cross(b,*this);
}所有三个成员函数都可以有效地共存和重用彼此的代码,如图所示。
https://stackoverflow.com/questions/17318603
复制相似问题