delete又未完全delete

反直觉C++🔥, 👏欢迎github star

delete又未完全delete

假设我们要定义一个这样的类:只支持拷贝操作不支持移动操作。

C++ 复制代码
#include <iostream>

class Test {
public:
    Test() {
        std::cout << "constructor\n";
    }

    Test(const Test& test) {
        std::cout << "copy constructor\n";
    }
    Test& operator=(const Test& test) {
        std::cout << "copy assignment operator\n";
        
        return *this;
    };

    Test(Test&& test) = delete;
    Test& operator=(Test&& test) = delete;
};

Test getTest() {
    Test test;
    return test;
}

int main() {
    Test test{ getTest() };

    return 0;
}

输出

C++ 复制代码
main.cpp: In function 'Test getTest()':
main.cpp:16:12: error: use of deleted function 'Test::Test(Test&&)'
   16 |     return test;
      |            ^~~~
main.cpp:10:5: note: declared here
   10 |     Test(Test&& test) = delete;
      |     ^~~~
main.cpp:16:12: note: use '-fdiagnostics-all-candidates' to display considered candidates
   16 |     return test;
      |            ^~~~

从编译错误信息可以看出,被显式deleteTest(Test&& test)参与到了重载决议,且被认为比拷贝构造版本更好,但移动构造版本被指定了删除不能被使用,所以编译器报错。 指定了删除,却未完全删除,参与到了重载决议,有点反直觉。

奇怪的知识增加了

删除的移动构造函数仍然是一个已声明的函数,有资格进行重载解析。getTest函数按值返回将优先选择删除的移动构造函数而非未删除的复制构造函数。

C++ 复制代码
#include <iostream>

class Test {
public:
    Test() {
        std::cout << "constructor\n";
    }

    Test(const Test& test) {
        std::cout << "copy constructor\n";
    }
    Test& operator=(const Test& test) {
        std::cout << "copy assignment operator\n";
        
        return *this;
    };

    Test(Test&& test) = default;
    Test& operator=(Test&& test) = delete;
};

Test getTest() {
    Test test;
    return test;
}

int main() {
    Test test{ getTest() };

    return 0;
}

输出

C++ 复制代码
constructor
C++ 复制代码
#include <iostream>

class Test {
public:
    Test() {
        std::cout << "constructor\n";
    }

    Test(const Test& test) {
        std::cout << "copy constructor\n";
    }
    Test& operator=(const Test& test) {
        std::cout << "copy assignment operator\n";
        
        return *this;
    };

    Test(Test&& test) {
        std::cout << "move constructor\n";
    }
    Test& operator=(Test&& test) = delete;
};

Test getTest() {
    Test test;
    return test;
}

int main() {
    Test test{ getTest() };

    return 0;
}

输出

C++ 复制代码
constructor

Test(Test&& test) = delete修改为Test(Test&& test) = default或者显式定义虽可以修复此问题,然而,之前的本意就是将移动构造删除,让其使用拷贝构造啊,如此修改违背了本意。 更进一步的观察,竟然未输出move constructor!重载决议选择了移动构造,但未执行移动构造,有点反直觉,此问题请参考尾返回值优化。

C++11之前可以通过"只声明不实现"的方式要删除函数,既然尾返回值优化可以优化掉拷贝构造的调用,那我们可以保证编译通过即可。

C++ 复制代码
#include <iostream>

class Test {
public:
    Test() {
        std::cout << "constructor\n";
    }

    Test(const Test& test) {
        std::cout << "copy constructor\n";
    }
    Test& operator=(const Test& test) {
        std::cout << "copy assignment operator\n";
        
        return *this;
    };

    Test(Test&& test);
    Test& operator=(Test&& test) = delete;
};

Test getTest() {
    Test test;
    return test;
}

int main() {
    Test test{ getTest() };

    return 0;
}

输出

C++ 复制代码
constructor

从上述代码表现来看,移动构造只参与了重载决议,未参与链接和运行期运行!

最后我们再尝试一个移动构造参与链接器链接的版本:

C++ 复制代码
#include <iostream>

class Test {
public:
    Test() {
        std::cout << "constructor\n";
    }

    Test(const Test& test) {
        std::cout << "copy constructor\n";
    }
    Test& operator=(const Test& test) {
        std::cout << "copy assignment operator\n";
        
        return *this;
    };

    Test(Test&& test);
    Test& operator=(Test&& test) = delete;
};

Test getTest() {
    Test test;
    return std::move(test);
}

int main() {
    Test test{ getTest() };

    return 0;
}

输出

C++ 复制代码
/tmp/cc3TH4WE.o: In function `getTest()':
main.cpp:(.text+0x32): undefined reference to `Test::Test(Test&&)'
collect2: error: ld returned 1 exit status

重载决议选择了移动构造,但是链接时未找到移动构造的实现!

相关推荐
Chester_19997 分钟前
CSP202312C.树上搜索
开发语言·数据结构·c++·蓝桥杯·stl
见叶之秋1 小时前
【C++】String类的使用(含模拟实现)
java·开发语言·c++
wuminyu2 小时前
Linux内核线程调度与虚拟线程调度机制系统级深度剖析
java·linux·c语言·jvm·c++
xxwxx__3 小时前
深入理解 C++ 继承:从基础语法到底层原理全解析
c++
键盘会跳舞3 小时前
【C++多线程】多线程性能调优:伪共享、缓存行对齐与吞吐优化
c++·多线程·多线程调优
学习星球4 小时前
编辑距离——二维 DP 的“最小操作“艺术
c++·leetcode·java-consul
OPEN-F4 小时前
ROS2系列教程:tf2坐标变换详解(C++/Python)
开发语言·c++·python
暖焰核心4 小时前
迭代器与模板的结合——stl的list
c++·windows·list
j7~4 小时前
【C++】C++的IO流--详解
c++·c++io流·c++流的概念·stringstream的介绍·c语言的输入与输出
zh_xuan5 小时前
c++ string_view
开发语言·c++