首页 > 编程语言 >第18 章探讨 C++新标准 移动构造函数解析,强制移动

第18 章探讨 C++新标准 移动构造函数解析,强制移动

时间:2024-08-13 18:52:08浏览次数:16  
标签:int 18 运算符 pc Useless 赋值 移动 构造函数

第18 章探讨 C++新标准 移动构造函数解析,强制移动

第18 章探讨 C++新标准 移动构造函数解析,强制移动

文章目录


18.2.5强制移动

移动构造函数和移动赋值运算符使用右值。如果要让它们使用左值,该如何办呢?例如,程序可能分析一个包含候选对象的数组,选择其中一个对象供以后使用,并丢弃数组。如果可以使用移动构造函数或移动赋值运算符来保留选定的对象,那该多好啊。然而,假设您试图像下面这样做:

Useless choices10];
Useless best;
int pick;
...//select one object,set pick to indexbest =choices[pick];

由于 choices[pick]是左值,因此上述赋值语句将使用复制赋值运算符,而不是移动赋值运算符。但如果能让 choices[pick]看起来像右值,便将使用移动赋值运算符。为此,可使用运算符static cast>将对象的类型强制转换为Useless&&,但C++11提供了一种更简单的方式–使用头文件utility 中声明的函数std::move()。程序清单18.3 演示了这种技术,它在 Useless 类中添加了啰嗦的赋值运算符,并让以前啰嗦的构造函数和析构函数保持沉默。

程序清单 18.3stdmove.cpp

// stdmove.cpp -- using std::move()
#include <iostream>
#include <utility>
// use the following for g++4.5
// #define nullptr 0
// interface
class Useless
{
private:
    int n;          // number of elements
    char * pc;      // pointer to data
    static int ct;  // number of objects
    void ShowObject() const;
public:
    Useless();
    explicit Useless(int k);
    Useless(int k, char ch);
    Useless(const Useless & f); // regular copy constructor
    Useless(Useless && f);      // move constructor
    ~Useless();
    Useless operator+(const Useless & f)const;
    Useless & operator=(const Useless & f); // copy assignment
    Useless & operator=(Useless && f);      // move assignment 
    void ShowData() const;
};

// implementation
int Useless::ct = 0;

Useless::Useless()
{
    ++ct;
    n = 0;
    pc = nullptr;
 }

Useless::Useless(int k) : n(k)
{
    ++ct; 
    pc = new char[n];
}

Useless::Useless(int k, char ch) : n(k)
{
    ++ct;
    pc = new char[n];
    for (int i = 0; i < n; i++)
        pc[i] = ch;
}

Useless::Useless(const Useless & f): n(f.n) 
{
    ++ct;
    pc = new char[n];
    for (int i = 0; i < n; i++)
        pc[i] = f.pc[i];
}

Useless::Useless(Useless && f): n(f.n) 
{
    ++ct;
    pc = f.pc;       // steal address
    f.pc = nullptr;  // give old object nothing in return
    f.n = 0;
}

Useless::~Useless()
{
    delete [] pc;
}

Useless & Useless::operator=(const Useless & f)  // copy assignment
{
    std::cout << "copy assignment operator called:\n";
    if (this == &f)
        return *this;
    delete [] pc;
    n = f.n;
    pc = new char[n];
    for (int i = 0; i < n; i++)
        pc[i] = f.pc[i];
    return *this;
}

Useless & Useless::operator=(Useless && f)       // move assignment
{
    std::cout << "move assignment operator called:\n";
    if (this == &f)
        return *this;
    delete [] pc;
    n = f.n;
    pc = f.pc;
    f.n = 0;
    f.pc = nullptr;
    return *this;
}

Useless Useless::operator+(const Useless & f)const
{
    Useless temp = Useless(n + f.n);
    for (int i = 0; i < n; i++)
        temp.pc[i] = pc[i];
    for (int i = n; i < temp.n; i++)
        temp.pc[i] = f.pc[i - n];
    return temp;
}

void Useless::ShowObject() const
{ 
    std::cout << "Number of elements: " << n;
    std::cout << " Data address: " << (void *) pc << std::endl;
}

void Useless::ShowData() const
{
    if (n == 0)
        std::cout << "(object empty)";
    else
        for (int i = 0; i < n; i++)
            std::cout << pc[i];
    std::cout << std::endl;
}

// application
int main()
{
    using std::cout;
    {
        Useless one(10, 'x');
        Useless two = one +one;   // calls move constructor
        cout << "object one: ";
        one.ShowData();
        cout << "object two: ";
        two.ShowData();
        Useless three, four;
        cout << "three = one\n";
        three = one;              // automatic copy assignment
        cout << "now object three = ";
        three.ShowData();
        cout << "and object one = ";
        one.ShowData();
        cout << "four = one + two\n";
        four = one + two;         // automatic move assignment
        cout << "now object four = ";
        four.ShowData();
        cout << "four = move(one)\n";
        four = std::move(one);    // forced move assignment
        cout << "now object four = ";
        four.ShowData();
        cout << "and object one = ";
        one.ShowData();
    }
     std::cin.get();
}

正如您看到的,将 one 赋给 three 调用了复制赋值运算符,但将 move(one)赋给 four 调用的是移动赋值运算符。
需要知道的是,函数 std:move()并非一定会导致移动操作。例如,假设 Chunk 是一个包含私有数据的类,而您编写了如下代码:

Chunk one;
.
Chunk two;
two =std::move(one);/move semantics?

表达式 std:move(one)是右值,因此上述赋值语句将调用 Chunk 的移动赋值运算符–如果定义了这样的运算符。但如果 Chunk 没有定义移动赋值运算符,编译器将使用复制赋值运算符。如果也没有定义复
制赋值运算符,将根本不允许上述赋值。对大多数程序员来说,右值引用带来的主要好处并非是让他们能够编写使用右值引用的代码,而是能够使用利用右值引用实现移动语义的库代码。例如,STL类现在都有复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符。

标签:int,18,运算符,pc,Useless,赋值,移动,构造函数
From: https://blog.csdn.net/zhyjhacker/article/details/141171289

相关文章

  • leetcode面试经典150题- 189. 轮转数组
     https://leetcode.cn/problems/rotate-array/description/?envType=study-plan-v2&envId=top-interview-150  gopackageleetcode150import"testing"funcTestRotate(t*testing.T){nums:=[]int{1,2}rotate2(nums,3)for_,num......
  • 代码随想录算法训练营第 42 天 |LeetCode 188.买卖股票的最佳时机IV LeetCode309.最佳
    代码随想录算法训练营Day42代码随想录算法训练营第42天|LeetCode188.买卖股票的最佳时机IVLeetCode309.最佳买卖股票时机含冷冻期LeetCode714.买卖股票的最佳时机含手续费目录代码随想录算法训练营前言LeetCode188.买卖股票的最佳时机IVLeetCode309.最佳买卖......
  • C++——构造函数和析构函数
    一、初识构造函数和析构函数简单来说,有对象生成必然会调用构造函数,有对象销毁必然会调用析构函数。构造函数的作用是初始化成员变量,是由编译器去调用的,而析构函数同理也是由编译器调用,不过他的作用则是清理。可以由下面的代码体验两个函数的使用。注意:相同点:两个函数都没有......
  • ARC182 题解
    A-ChmaxRush!发现一个数能向哪边覆盖只由再他之后操作且\(v\)比他大的操作决定。所以扫一遍确定方向之后乘起来就好。B-|{floor(A_i/2^k)}|首先不难发现\(<2_{k-1}\)的元素是无用的,因为它们会由\(\ge2^{k-1}\)的元素除以2的幂得到。先想上界。对于\(0\l......
  • ARC182B |{floor(A_i/2^k)}| 题解
    ARC182B|{floor(A_i/2^k)}|题解题目大意定义一个长度为\(N\)的序列\(A\)的分数为能被表示成\(\lfloor{A_i\over2^k}\rfloor\)的数的个数,其中\(i=1,2,\dots,N\),\(k\)为任意自然数。给定\(N,K\),求长度为\(N\)且元素大小都在\(2^K-1\)内的所有序列的分数的最大值......
  • [ARC182F] Graph of Mod of Linear
    MyBlogs[ARC182F]GraphofModofLinear首先判掉\(A\leq1\)的情况,接下来默认\(A\geq2\)。原图是基环树森林,数连通块数等价于数环的个数。比较自然的一点是,把问题分为\(A,N\)是否互质。因为如果\(A\)和\(N\)互质,则\(Ai+B\)在\(\modN\)意义下互不相同,所以每个......
  • ARC182C
    题目C-SumofNumberofDivisorsofProduct定义一个合法的序列为:长度在\([1,n]\)间,且每个元素均为\([1,m]\)中整数的序列。定义一个合法序列的权值为:令\(X\)为序列中所有元素的乘积,则权值为\(X\)的约数个数。对所有\(\sum_{k=1}^nm^k\)个合法序列,求它们的......
  • Java基础入门18:File、IO 流1(方法递归、字符集、IO流-字节流)
    File和IO流FileFile是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。IO流用于读写数据的(可以读写文件,或网络中的数据...)File代表文件IO流用来读写数据File创建对象创建File类的对象注意:File对象既可以代表文件、也可以代表文......
  • JS中关于为什么调用构造函数要使用new的详细解读
    在JavaScript中,使用new关键字调用构造函数是创建新对象的关键步骤。本文将从以下几个方面解释为什么要这样做:1.创建一个新的对象当你用new调用构造函数时,会自动创建一个新的空对象,这个对象会被赋值给this,即构造函数内部的this关键字会引用这个新创建的对象。fu......
  • AT_arc181_c [ARC181C] Row and Column Order
    思路简单。首先我们可以考虑按着\(p\)数组的顺序遍历。接着因为题目要求字典序最小,我们可以将\(q\)数组倒着来讲后面\(i\)个标记为\(1\),此时我们保证了\(p\)数组中是字典序从小到大的,又保证了\(q\)数组中是按照字典序排序的。代码#include<bits/stdc++.h>usingn......