不要返回 T&&。
我想创建一些类,并通过一系列修改类的函数传递类。然后我将评估该类的一些成员,或者将该类存储在某个容器中,例如std::vector
.
我试图以这样一种方式做到这一点,即该类只构造一次,然后被销毁或移动,并且移动的副本被销毁,然后存储的副本被销毁(当我存储它的容器被销毁时) .
本质上,我想这样做:
// some class
class foo{}
// construct a foo, with some parameters, and modify it somehow
auto f1 = modify_foo(foo(x, y, z));
// modify the foo some more
auto f2 = modify_foo(f1);
// modify the foo some more
auto f3 = modify_foo(f2);
// use some element of modified foo
auto v = f3.getx();
// maybe store the modified foo in a vector or some other container
vector<foo> vf;
vf.emplace_back(f3);
应该可以构造foo
恰好一次,并foo
通过任意数量的修改函数移动构造,然后销毁foo
恰好一次。
如果将 存储foo
在 a 中vector
,则必须进行额外的复制/移动和销毁。
我可以实现这种行为,但是如果不将此签名用于修改功能,我想不出任何方法:
foo&& modify_foo(foo&& in);
这是似乎可以满足我要求的测试代码:
#include <iostream>
#include <functional>
#include <vector>
// A SIMPLE CLASS WITH INSTRUMENTED CONSTRUCTORS
class foo {
public:
// default constructor
foo() {
std::cout << "default construct\n";
}
// copy constructor
foo(foo const &in) : x{ in.x } {
std::cout << "copy construct\n";
};
// copy assignment
foo& operator=(foo const& in) {
x = in.x;
std::cout << "copy assignment\n";
}
// move constructor
foo(foo&& in) noexcept : x(std::move(in.x)) {
std::cout << "move constructor\n";
}
// move assignment
foo& operator=(foo&& in) noexcept {
x = std::move(in.x);
std::cout << "move assignment\n";
return *this;
}
// destructor
~foo() {
std::cout << "destructor\n";
}
void inc() {
++x;
}
int getx() { return x; };
private:
int x{ 0 };
};
现在一个函数将接受foo&&
、修改foo
、返回foo&&
:
// A SIMPLE FUNCTION THAT TAKES foo&&, modifies something, returns foo&&
foo&& modify(foo&& in) {
in.inc();
return std::move(in);
}
现在使用类和修改功能:
int main(){
// construct a foo, modify it, return it as foo&&
auto&& foo1 = modify(foo());
// modify foo some more and return it
auto&& foo2 = modify(std::move(foo1));
// modify foo some more and return it
auto&& foo3 = modify(std::move(foo2));
// do something with the modified foo:
std::cout << foo3.getx();
}
这将完全符合我的要求。它将调用一次构造函数,正确地打印3
,并调用一次析构函数。
如果我做同样的事情,除了添加这个:
std::vector<foo> fv;
fv.emplace_back(std::move(foo3));
它将添加一个移动构造,并在vector
超出范围时破坏另一个。
这正是我想要的行为,而且我还没有想出任何其他方法可以在不foo&&
从修饰符返回的情况下到达那里,并使用auto&&
我的中间变量,并使用std::move()
传递给后续调用的参数modify
。
这种模式对我非常有用。困扰我的是,我无法使用 CPP 核心指南 F.45 解决这个问题。该指南确实说:
当对临时对象的引用“向下”传递给被调用者时,返回右值引用就可以了;那么临时保证比函数调用更长寿......
也许这就是我正在做的?
我的问题:
我正在做的事情有什么根本错误或未定义的吗?
当我这样做
auto&&
并将鼠标悬停在 上时foo1
,它将显示为foo&&
. 我仍然必须将 with 包装foo1
起来std::move(foo1)
才能让 modify 函数将其接受为foo&&
. 我觉得这有点奇怪。需要这种语法的原因是什么?