首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11构造函数

C++11构造函数
EN

Stack Overflow用户
提问于 2013-06-26 19:18:34
回答 4查看 360关注 0票数 4

新的移动构造函数/移动运算符允许我们转移对象的所有权,这样就避免了使用(昂贵的)复制构造函数调用。但是有没有可能避免构造临时对象(不使用返回参数)?

示例:在下面的代码中,构造函数被调用了4次-但理想情况下,我想要做的是避免在cross方法中构造任何对象。使用返回参数(例如void cross(const Vec3 &b, Vec3& out) )是可能的,但读起来很难看。我对更新现有变量很感兴趣。

代码语言:javascript
复制
#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;
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-06-26 19:54:04

另一种解决方案是从a.cross(b)返回一个“表达式对象”,将计算推迟到这样的对象被分配给c,然后在operator=中实际执行计算:

代码语言:javascript
复制
 struct Vec3
 {

      CrossProduct cross(const Vec3& b);

      Vec3& operator=(CrossProduct cp)
      {
          do calculation here putting result in `*this`
      }
 }

并添加类似的构造机制等等。

这比较复杂,但许多C++数学库都使用这种设计模式。

票数 4
EN

Stack Overflow用户

发布于 2013-06-26 19:25:48

如果您直接分配新值:

代码语言:javascript
复制
Vec3 a = b.cross(c);

那么RVO就有可能会生效,并且不会有临时的构造和移动。确保您正在使用优化进行编译。返回值将被就地构造为。

另外,在堆上分配3个浮点数的数组似乎是一个性能杀手。使用类似C的数组float p[3]std::array<float, 3>应该会执行得更好。

票数 2
EN

Stack Overflow用户

发布于 2013-06-26 19:31:21

要更新现有变量,可以使用out参数:

代码语言:javascript
复制
// 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将省略构造函数:

代码语言:javascript
复制
// return value version (RVO)
Vec3 cross(const Vec3& b)
{
    Vec3 t; cross(b, t); return t;
}

您还可以提供result对象的赋值函数:

代码语言:javascript
复制
// assignment version
void set_cross(const Vec3& a, const Vec3& b)
{
    a.cross(b,*this);
}

所有三个成员函数都可以有效地共存和重用彼此的代码,如图所示。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17318603

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档