C++中的移动构造函数

学习了移动构造,不太清楚它到底什么时候使用,感觉他是把原来的指针置空,然后重新分配一个指针指向这块内存。既然是和指针有关系,那是不是只能在堆区分配空间的时候才能用到?

说白了移动构造函数就是可以避免不必要的复制操作,提高程序的效率。不只限于堆区,像使用容器操作,创建临时对象时都可以避免不必要的复制操作

  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/7736800
  • 你也可以参考下这篇文章:C++实现输入任意数,将其拆分成若干个素数的乘积,判断一个数是否可以由两个素数相乘得到,给定一个范围,计算在这个范围内那些数可以是两个素数的乘积
  • 除此之外, 这篇博客: C++跳到指定行开始读取指定的列数据中的        在读取大容量数据的时候,前面的几行常常包括文件的说明,所以读取的时候应该去掉,而且我们经常需要读取文件中的指定列的数据。下面的例子演示了这个功能: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • //定位到txt文件的某一行
    ifstream & seek_to_line(ifstream & in, int line)
    //将打开的文件in,定位到line行。
    {
    	int i;
    	char buf[1024];
    	in.seekg(0, ios::beg);  //定位到文件开始。
    	for (i = 0; i < line; i++)
    	{
    		in.getline(buf, sizeof(buf));//读取行。
    	}
    	return in;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	//读取文件路径
    	std::string pts_filename = "E:/数据文件/20190718.txt";
    	std::vector<Point3D> pts;
    	{
    		std::ifstream pts_file;
    		pts_file.open(pts_filename);
    		seek_to_line(pts_file, 2);  //定位到指定的行开始读取
    		if (!pts_file.is_open())
    		{
    			cout << "Unable to open myfile";
    			system("pause");
    			exit(1);
    		}
    		while (!pts_file.eof())
    		{
                //先忽略前面的2列,从第三列开始读取,读取了3-5列x,y,z的数据保存到point3D中,然后
                //当前行后面的数据全部忽略
    			for (Point3D pt; (((pts_file >> ws).ignore(numeric_limits<streamsize>::max(), ' ') >> ws).ignore(numeric_limits<streamsize>::max(), ' ') >> pt.x >> pt.y >> pt.z >> ws).ignore(numeric_limits<streamsize>::max(), '\n');)
    			{
    				pts.push_back(pt);     //将数据保存下来
    			}
    		}
    		pts_file.close();
    	}
    	return 0;
    }
    
    

           由于后来需要用到一些windows的函数,出现了编译错误,参考了链接:https://blog.csdn.net/huixingshao/article/details/86534865。std::numeric_limits::max()使用的是STL中的z数值极限<Numeric Limits>,如果又添加了#include<windows.h>则会出现如下错误: 

    warning     C4003:     “max”宏的实参不足       
    error     C2589:     “(”     :     “::”右边的非法标记

    因为需要把max用括号括起来避免和windows定义的宏混淆

    (std::numeric_limits<double>::max)()

    因为Windef.h中定义了

    #ifndef max
    #define max(a,b)            (((a) > (b)) ? (a) : (b))
    #endif

    所以会产生编译错误。

  • 您还可以看一下 夏曹俊老师的C++ 设计模式原理与实战大全-架构师需备课程课程中的 适配器模式的定义、场景与实用工程技术:对象适配与类的适配小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    移动构造函数是C++11引入的一种特殊类型的构造函数,用于将右值引用的对象的资源(比如堆空间、文件句柄等)转移给另一个对象,而不是发生一次深拷贝。移动构造函数通常用于提高程序的性能和效率,尤其在处理大规模的数据时更为明显。

    当一个类重载了移动构造函数时,如果类的对象要被移动而不是被拷贝,就会调用移动构造函数。移动构造函数的形式为“类名(类名&&)”。其中“&&”表示右值引用。

    下面给出一个简单的例子,展示了如何在类中重载移动构造函数:

    #include <iostream>
    #include <string>
    #include <utility>
    
    class MyClass {
    public:
        // 普通构造函数
        MyClass(std::string s) : str_(std::move(s)) {
            std::cout << "Constructing MyClass with string: " << str_ << std::endl;
        }
    
        // 移动构造函数
        MyClass(MyClass&& other) : str_(std::move(other.str_)) {
            std::cout << "Moving contents from MyClass with string: " << str_ << std::endl;
        }
    
    private:
        std::string str_;
    };
    
    int main() {
        MyClass a("Hello, world!");  // 普通构造函数
        MyClass b(std::move(a));    // 使用 std::move 移动 a 中的数据到 b 中
        return 0;
    }
    

    在这个例子中,我们定义了一个 MyClass 类,含有一个普通构造函数和一个移动构造函数。在主函数中,我们首先使用普通构造函数创建了一个 MyClass 对象 a。然后,我们使用 std::move 将 a 中的资源(即字符串 "Hello, world!")移动到 b 对象中,这里将会调用移动构造函数。

    需要注意的是,移动构造函数并不会释放被移动对象的资源,被移动对象还是需要进行析构,只不过其资源已经转移给了新创建的对象。所以,在移动构造函数中,我们通常需要将被移动对象的指针或者引用设置为空,避免被移动对象和移动后的对象同时拥有相同的资源。

    移动构造函数往往可以应用于对象的智能指针和容器(比如 vector)等场景中,可以大大提高程序的效率。