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

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

相关推荐
端平入洛1 天前
auto有时不auto
c++
哇哈哈20212 天前
信号量和信号
linux·c++
多恩Stone2 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
蜡笔小马2 天前
21.Boost.Geometry disjoint、distance、envelope、equals、expand和for_each算法接口详解
c++·算法·boost
超级大福宝2 天前
N皇后问题:经典回溯算法的一些分析
数据结构·c++·算法·leetcode
weiabc2 天前
printf(“%lf“, ys) 和 cout << ys 输出的浮点数格式存在细微差异
数据结构·c++·算法
问好眼2 天前
《算法竞赛进阶指南》0x01 位运算-3.64位整数乘法
c++·算法·位运算·信息学奥赛
yyjtx2 天前
DHU上机打卡D31
开发语言·c++·算法
czxyvX2 天前
020-C++之unordered容器
数据结构·c++