C++11构造函数
C++11 constructors
新的移动构造函数/move运算符允许我们转移对象的所有权,这样就避免了使用(昂贵的)复制构造函数调用。但是,是否可以避免构建临时对象(不使用返回参数)?
示例:在下面的代码中,构造函数被调用了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;
}
另一种解决方案是从a.cross(b)
返回一个"表达式对象",定义计算,直到将这样的对象分配给c
,然后在operator=
中实际执行计算:
struct Vec3
{
CrossProduct cross(const Vec3& b);
Vec3& operator=(CrossProduct cp)
{
do calculation here putting result in `*this`
}
}
并添加类似的构造机制等等
这更为复杂,但许多C++数学库都使用这种设计模式。
如果直接分配新值:
Vec3 a = b.cross(c);
然后,RVO可能会生效,以后不会临时建造和移动。请确保使用优化进行编译。返回的值将被构造成一个
此外,在堆上分配一个由3个浮点组成的数组似乎是一个性能杀手。使用类C阵列CCD_ 5或CCD_。
要更新现有变量,可以使用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;
}
当返回值版本用作初始值设定项时,RVO将省略构造函数(,但当分配给现有对象时不会):
// return value version (RVO)
Vec3 cross(const Vec3& b)
{
Vec3 t; cross(b, t); return t;
}
此外,您还可以提供一个结果对象的变体:
// assignment version
void set_cross(const Vec3& a, const Vec3& b)
{
a.cross(b,*this);
}
所有三个成员函数都可以有效地共存并重用彼此的代码,如图所示。
这不是对您问题的直接回答,我只能贡献很少,因为目前的答案涵盖了要点,但我想让您注意到您选择的基于堆的设计的缺点。
3d矢量很少单独出现
当然,这是一种权衡,取决于你必须进行的移动次数和对向量执行的操作次数。
如果你只使用一些单一的向量,并且做了很多复制/移动的事情,你可以坚持你的堆基础设计。但是,如果您有几个向量(例如,在一个向量或数组中),并且您想对它们进行操作,如果您担心性能,我建议您不要进行堆分配。
std::vector<Vec3> a(20);
class con_Vec3 { double x, y, z; };
std::vector<con_Vec3> b(20);
向量a
将保持一个指向浮点的连续指针块,而浮点值将位于内存中的其他位置,这意味着您的值实际上分散在内存中。相反,向量b
将包含60个double
s的连续块,全部在一个位置。
对于这两种情况,移动这样的std::vector
的成本都是相等的(每种情况都是准交换),但如果复制它们,基于堆的解决方案会更慢,因为将进行21个分配和20个拷贝,而在非堆解决方案中,有一个分配和两个拷贝覆盖整个向量。
- 继承:构造函数,初始化C++11中基类的类C数组成员
- C++11:没有复制构造函数的自定义基于范围的循环
- 如何在C++11中区分填充构造函数和范围构造函数
- 移动构造函数 C++11
- 构造函数中调用没有匹配函数 - C++ 11
- 防止复制构造函数实例化 C++11 类"deleting"
- =删除用户定义的成员功能,除了构造函数,分配运算符C 11
- SFINAE enable_if 使用 pre c++11 启用构造函数
- 为什么编译器在试图初始化具有C 11样式的对象数组时隐含删除构造函数
- 摘要类可以在C 11中具有构造函数和私人成员
- C 11:可以默认默认构造函数导致部分初始化类
- C 11和类构造函数中的variadic模板
- C 11多移动构造函数调用
- 具有类成员默认值的 C++11 默认构造函数行为
- 如何避免在 c++11 中触发这种复制构造函数?
- 带有C 11继承的构造函数的警告
- 没有C 11的继承构造函数
- 在C++11中按值返回构造的对象时,避免复制构造函数调用
- C++11 cmake O3 选项<没有用于初始化 'std::thread' 的匹配构造函数>
- 为什么 C++11 从 std::vector 的填充构造函数的原型中删除了默认值?