之前一直对右值引用能带来什么收益感到困惑,最近总结出了右值引用的优点。
右值引用的技术点包括:std::move,std::forward,类中的移动构造函数和移动拷贝函数。
要理解右值引用带来什么收益,需要从两个角度去思考这个问题。
1,一个角度就是提供函数服务,或者容器服务的一方。一般是通过函数接口提供服务,函数接口一般需要调用者传入一个对象作为入参。所谓的右值引用就是对这个对象提供普通引用和右值引用两个重载函数。
2,第二个角度是针对作为入参的类,我们一般需要对这个类实现移动构造函数和移动赋值构造函数。
所有的收益就体现在整个系统能够触发入参类的移动构造函数或者移动赋值函数,从而达成浅拷贝提升性能。
当然右值引用约定了一些语义需要我们去遵循,例如通过std::move(入参对象)去传递右值后,我们不应该再去操作入参对象。
另外std::forward是用于在模板中实现完美转发的功能。
也就是所谓的std::move一般用于普通函数,std::forward用于模板函数。
下面给出右值引用的一些经典实现:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <filesystem>
#include <vector>
template <typename T>
class Executor {
public:
inline bool enqueue(const T& element)
{
std::cout << "enqueue &\n";
m_data = std::move(const_cast<T&>(element));
//m_data = std::move(element);
return true;
}
inline bool enqueue(T&& element)
{
std::cout << "enqueue &&\n";
m_data = std::move(element);
return true;
}
bool enqueueWithTimeout(T&& element, uint64_t timeout);
private:
T m_data{ 1 };
};
template<typename T>
bool Executor<T>::enqueueWithTimeout(T&& element, uint64_t timeout)
{
enqueue(std::forward<T>(element));
return true;
}
class Elment {
public:
explicit Elment(int i) :size_(0), data_(nullptr), t_(i) {
std::cout << "Elment:" << t_ << std::endl;
}
//Elment(const Elment& other) {
Elment(const Elment& other) {
std::cout << "Elment&:" << t_ << ",other:" << other.t_ << std::endl;
if (this == &other) {
return;
}
data_ = new int[other.size_];
size_ = other.size_;
for (int i = 0; i < other.size_; i++) {
data_[i] = other.data_[i];
}
t_ = other.t_;
}
Elment(Elment&& other) {
std::cout << "Elment&&:" << t_ << ",other:" << other.t_ << std::endl;
if (this == &other) {
return;
}
data_ = other.data_;
size_ = other.size_;
other.data_ = nullptr;
other.size_ = 0;
t_ = other.t_;
other.t_ = -1;
}
virtual ~Elment() noexcept {
std::cout << "~Elment:" << t_ << std::endl;
}
Elment& operator=(const Elment& other) noexcept {
std::cout << "copy Elment&:" << t_ << ",other:" << other.t_ << std::endl;
if (this == &other) {
return *this;
}
if (data_) {
delete[] data_;
}
data_ = new int[other.size_];
size_ = other.size_;
t_ = other.t_;
for (int i = 0; i < other.size_; i++) {
data_[i] = other.data_[i];
}
return *this;
}
Elment& operator=(Elment&& other) noexcept {
std::cout << "copy Elment&&:" << t_ << ",other:" << other.t_ << std::endl;
if (this == &other) {
return *this;
}
if (data_) {
delete[] data_;
}
data_ = other.data_;
size_ = other.size_;
t_ = other.t_;
other.t_ = -1;
other.data_ = nullptr;
other.size_ = 0;
return *this;
}
private:
int size_ = 0;
int* data_;
int t_ = 1;
};
int main()
{
//Executor<Elment> exe;
//Elment b = a;
//Elment c = std::move(a);
//Elment d = std::move(a);
//exe.enqueue(std::move(b));
//exe.enqueueWithTimeout(std::move(a), 100);
//exe.enqueueWithTimeout(std::move(a), 100);
//exe.enqueue(a);
std::vector<Elment> vec;
{
std::vector<Elment> vec1;
//vec1.push_back(Elment(101));
vec1.emplace_back(101);
//vec = vec1;
vec = std::move(vec1);
std::cout << vec1.size() << std::endl;
}
std::cout << "return \n";
//vec.emplace_back(101);
return 0;
}