c++ move,可变参数模板,折叠表达式,...

本文介绍了C++中的移动语义,包括右值引用的使用、移动构造函数和移动赋值运算符的作用,以及如何通过移动语义实现更高效的资源管理和避免深拷贝。还讨论了可变参数模板和折叠表达式的应用,以及std::forward在完美转发中的作用。
摘要由CSDN通过智能技术生成

std::move与移动语义

移动语义是C++中的一个概念,它引入了一种新的方式来处理数据的传递和拷贝。在传统的拷贝语义中,当你将一个对象赋值给另一个对象或传递给函数时,会执行深拷贝,即复制对象的内容。而在移动语义中,当你将一个对象的资源(例如堆上分配的内存)转移到另一个对象时,不再复制资源,而是将所有权转移到新的对象,同时原对象保持有效但处于有效但未指定的状态。这允许更高效的资源管理,减少了深拷贝的开销。

C++11 引入了右值引用和移动语义,使得编译器能够区分左值(通常是具名对象)和右值(临时对象、表达式结果等)。右值引用允许我们获取到右值,并使用它们的资源而不进行深拷贝。

移动语义的主要要点如下:

  1. 右值引用: 右值引用是一种新的引用类型,通过 && 表示。它允许我们绑定到临时对象或表达式的结果,而不仅仅是具名对象(左值)。

  2. 移动构造函数和移动赋值运算符: 类可以定义特殊的成员函数,即移动构造函数和移动赋值运算符,以便支持移动语义。这些函数允许在对象间转移资源,而不是进行深拷贝。

下面是一个简单的例子,演示了移动语义的基本概念:

#include <iostream>
#include <utility>

class MyString {
public:
    // 移动构造函数
    MyString(MyString&& other) noexcept
        : data(other.data) {
        other.data = nullptr;
    }

    // 移动赋值运算符
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            other.data = nullptr;
        }
        return *this;
    }

    // 普通构造函数和析构函数
    MyString(const char* str)
        : data(new char[strlen(str) + 1]) {
        std::strcpy(data, str);
    }

    ~MyString() {
        delete[] data;
    }

private:
    char* data;
};

int main() {
    MyString str1("Hello");

    // 移动构造函数
    MyString str2 = std::move(str1);

    // 移动赋值运算符
    MyString str3;
    str3 = std::move(str2);

    return 0;
}

在这个例子中,MyString 类实现了移动构造函数和移动赋值运算符,通过 std::move 可以显式地调用移动语义。移动构造函数和移动赋值运算符的 实现允许在对象之间高效地传递资源,而不进行深拷贝。

在C++中,你可以通过检查对象是否具有移动构造函数和移动赋值运算符来判断一个对象是否支持移动语义。

 promise<string> p;//支持移动语义
 auto fu = p.get_future(); //std::future<string>//必须在move之前,否则会抛异常
 auto re = std::thread(TestFuture, move(p));

可变参数模板Args… args

可变参数模板是C++11中的一种特性,它允许定义模板,接受可变数量的模板参数。这种功能对于处理不确定数量的参数或在泛型编程中非常有用。

以下是可变参数模板的基本语法:

template <typename... Args>
void myFunction(Args... args) {
    // 在函数体中使用参数包 Args...,对参数进行操作
}

上述代码中,Args... 表示一个模板参数包,它可以接受零个或多个类型参数。在函数体中,args... 是对参数包的展开,允许在函数中对可变数量的参数进行操作。

示例:

#include <iostream>

// 使用可变参数模板实现打印任意数量的参数
template <typename... Args>
void printArgs(Args... args) {
    (std::cout << ... << args) << std::endl;
}
int main() {
    // 调用可变参数模板
    printArgs(1, "Hello", 3.14, 'A');

    return 0;
}



//递归方式展开
template <class T, class ...Args>
void FormatPrint(T first, Args... args)//每次取第一个参数,然后剩下的打包,进行递归
{
   std::cout << "[" << first << "]";
   FormatPrint(args...);
}

在上述示例中,printArgs 函数是一个接受可变数量参数的模板函数,通过折叠表达式 (std::cout << ... << args) 将所有参数连接在一起并输出到标准输出流。

折叠表达式(c++17)

一元右折叠:(E op …) 展开为 (E1 op (… op (EN-1 op EN)))
一元左折叠:(… op E) 展开为 (((E1 op E2) op …) op EN)
二元右折叠:(E op … op I) 展开为 (E1 op (… op (EN−1 op (EN op I))))
二元左折叠:(I op … op E) 展开为 (((I op E1) op E2) op …) op EN

void printArgs(Args&&... args) {
    // 使用折叠表达式展开参数包
    (std::cout  << ... << args)<< std::endl;
    //二元左折叠展开为(((std::cout op E1) op E2) op …) op EN
}

std::forward<Args>(args)...样例

std::forward<Args>(args)... 是右折叠的语法形式,其中 Args 是模板参数包,... 表示右折叠。这个折叠表达式用于在函数模板中进行完美转发,确保传递的参数保持其原始的值类别(左值或右值)。

以下是 std::forward<Args>(args)... 的展开过程:

std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), ..., std::forward<ArgN>(argN)

这里,Arg1, Arg2, …, ArgN 是模板参数包 Args 中的各个参数。在展开过程中,std::forward<Arg1>(arg1) 表达式将参数 arg1 通过 std::forward 进行完美转发,保持其原始的值类别。展开后的结果是一系列逗号分隔的完美转发表达式。

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗯哼_Hello

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值