gpt4 book ai didi

c++ - move 语义以避免创建临时对象

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:30:01 27 4
gpt4 key购买 nike

我正在尝试在大型对象之间进行操作,并且我尝试使用 r 值引用来避免创建临时对象。实验是下面的代码,但是结果并不是我所期望的。

代码:

#include <iostream>
using namespace std;

struct A
{
A() = default;
A(const A& a) { cout << "copy ctor" << endl; }
A(A&& a) { cout << "move ctor" << endl; }
A &operator=(const A& a) { cout << "copy assign" << endl; return *this; }
A &operator=(A&& a) { cout << "move assign" << endl; return *this; }
A &operator*=(double s) { cout << "this = this *= s" << endl; return *this; }
A operator*(double s) const { cout << "A = const this * s" << endl; return *this; }
A &operator+=(const A &b) { cout << "this = this + const A&" << endl; return *this; }
A operator+(const A &b) const { cout << "A = const this + const A&" << endl; return *this; }
A &operator+(A &&b) const { cout << "A&& = const this + A&& --> "; return b += *this; }
};
A &operator+(A &&a, const A &b) { cout << "A&& = A&& + const A& --> "; return a += b; }
A &operator*(A &&a, double s) { cout << "A&& = A&& * s --> "; return a *= s; }

int main()
{
A a,b,c,d;
a = b + a * 4 + /*operator*(static_cast<A&&>(d), 2)*/ d * 2 + (A() + c) * 5;

return 0;
}

输出:

A&& = A&& + const A& --> this = this + const A&     // A() + c
A = const this * s // (...) * 5
copy ctor // ???
A = const this * s // d * 2
copy ctor // ???
A = const this * s // a * 4
copy ctor // ???
A&& = const this + A&& --> this = this + const A& // (d*2) + (...)
A&& = const this + A&& --> this = this + const A& // (a*4) + (...)
A&& = const this + A&& --> this = this + const A& // b + (...)
copy assign // a = (...)

我的期望:

A&& = A&& + const A& --> this = this + const A&     // A() + c
A&& = A&& * s --> this = this *= s // (...) * 5
A&& = A&& * s --> this = this *= s // (...) * 2 d is not used anymore, so I want to move semantics
A = const this * s // a * 4 a is not used anymore, but I want to keep semantics
A&& = A&& + const A& --> this = this + const A& // (d*2) + (...)
A&& = A&& + const A& --> this = this + const A& // (a*4) + (...)
A&& = A&& + const A& --> this = this + const A& // b + (...)
move assign // a = (...)

最佳答案

这是一个更正确的版本,但拷贝更少:

#include <iostream>
#include <utility>
using namespace std;

struct A
{
A() = default;
A(const A& a) { cout << "copy ctor" << endl; }
A(A&& a) { cout << "move ctor" << endl; }
A &operator=(const A& a) { cout << "copy assign" << endl; return *this; }
A &operator=(A&& a) { cout << "move assign" << endl; return *this; }
A &operator*=(double s) { cout << "this *= s" << endl; return *this; }
A &operator+=(const A &b) { cout << "this += const A&" << endl; return *this; }
};

A&& operator+(A &&a, const A &b)
{ cout << "A&& + const A&" << endl; a+=b; return std::move(a); }

A&& operator+(A &&a, A &&b)
{ cout << "A&& + A&&" << endl; a+=b; return std::move(a); }

// I assume commutativity
A&& operator+(const A &a, A &&b)
{ cout << "const A& + A&&" << endl; b+=a; return std::move(b); }

A operator+(const A &a, const A &b)
{ cout << "const A& + const A&" << endl; A r(a); r+=b; return r; }

A&& operator*(A &&a, double s)
{ cout << "A&& * s" << endl; a*=s; return std::move(a); }

A operator*(const A& a, double s)
{ cout << "const A& * s" << endl; A r(a); r*=s; return r; }

int main()
{
A a,b,c,d;
a = b + a * 4 + d * 2 + (A() + c) * 5;

return 0;
}

这里是(带注释的)输出,其中 t 是临时创建的:

                       expression level    actual operations
---------------- -----------------
const A& * s t1 = a * 4
copy ctor create t1 = copy a
this *= s t1 *= 4
const A& + A&& b + t1
this += const A& t1 += b
const A& * s t2 = d * 2
copy ctor create t2 = copy d
this *= s t2 *= 2
A&& + A&& t1 + t2
this += const A& t1 += t2
A&& + const A& A() + c (note: A() is already a temporary)
this += const A& A() += c
A&& * s A'() * 5
this *= s A'() *= 5
A&& + A&& t1 + A''()
this += const A& t1 += A''()
move assign a = t1 a = t1

我认为你不能期望它比整个表达式只有两个临时变量更好。

关于您注释掉的代码:尝试使用 std::move(d) 而不是普通的 d 并且您将保护 d 的拷贝> 在上面的输出中,将临时对象的数量减少到一个。如果您还添加了 std::move(a),整个表达式的计算没有一个临时值!

另请注意,如果没有 std::move(d)std::move(a),编译器不知道它应该/可以 move 这些对象,所以任何最终 move 它们的代码都是危险的,而且是完全错误的。


更新:我把我的想法变成了一个图书馆,可以在GitHub找到它。 .有了这个,您的代码变得如此简单:

#include <iostream>
using namespace std;

#include <df/operators.hpp>

struct A : df::commutative_addable< A >, df::multipliable< A, double >
{
A() = default;
A(const A& a) { cout << "copy ctor" << endl; }
A(A&& a) { cout << "move ctor" << endl; }
A &operator=(const A& a) { cout << "copy assign" << endl; return *this; }
A &operator=(A&& a) { cout << "move assign" << endl; return *this; }
A &operator*=(double s) { cout << "this *= s" << endl; return *this; }
A &operator+=(const A &b) { cout << "this += const A&" << endl; return *this; }
};

同时仍然高效并避免任何不必要的临时文件。享受吧!

关于c++ - move 语义以避免创建临时对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15597754/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com