C++ 11 =delete

前言

在写代码的时候发现一个bug,编译器报错,报

/usr/include/c++/9/ext/new_allocator.h:145:20: error: use of deleted function

最后发现了原因,是因为我们隐式的调用了copy构造函数,但是,copy构造函数被我们显示的删除了(=delete),由此我们探讨一下C++ 11的=delete特性

代码

先看一个正常的copy构造函数

#include <iostream>
#include <list>

using namespace std;

class A{
public:
    A(const A&){
		cout << "copy construct" << "\n";
	}
    
    A( int id)
    :class_id(id){
        cout << "normal construct" << "\n";
    }
    
private:
    int class_id;
    
};

int main()
{
    list<A> a;
    a.push_front(A(1));
    a.push_front(A(2));
    
    //cout<<"Hello World";

    return 0;
}

我们知道在一个list中push一个class会隐式的调用copy构造,或者移动构造,2者都存在先调用移动构造,具体看这里,因为项目的一些历史原因有的class的拷贝构造被赋予了=delete,这说明编译器明令禁止调用对应函数,所以会导致报错,我们看一下

#include <iostream>
#include <list>

using namespace std;

class A{
public:
    A(const A&) = delete; //注意这里
    
    A( int id)
    :class_id(id){
        cout << "normal construct" << "\n";
    }
    
private:
    int class_id;
    
};

int main()
{
    list<A> a;
    a.push_front(A(1));
    a.push_front(A(2));
    
    //cout<<"Hello World";

    return 0;
}

再看输出

/usr/include/c++/9/ext/new_allocator.h:145:20: error: use of deleted function ‘A::A(const A&)’

上述代码禁止我们使用Class A的拷贝构造函数,所以在push的时候隐式的调用copy构造是非法的

考虑一个更深层次的问题,为什么我们需要禁用拷贝构造函数?
我们知道拷贝构造函数会将其内存中的对应值都拷贝进另一个对象中,假如这个值非常的大就比较悲催了,所以我们在某一些场合会禁用拷贝构造
还有一种情况,我们的class中有个成员是动态数组,我们用拷贝构造将这个数组传入到新的class中,会导致有2个指针变量指向一个地址的情况,因为默认构造函数会尝试copy全部的成员…如下代码所示

#include <iostream>
#include <list>

using namespace std;

class A{
public:
    //A(const A&) = delete;
    
    A( int id, int d)
    :class_id(id),data(d){
        cout << "normal construct" << "\n";
    }
    
    int getclassid(){ return class_id; }
    int getdata(){ return data; }
    
private:
    int class_id;
    int data;
    
};

int main()
{
    A a(1,2);
    cout << "A's class id is " << a.getclassid() << " A's data is " << a.getdata()<<"\n" ; 
    A b = a;
    cout << "B's class id is " << b.getclassid() << " B's data is " << b.getdata() << "\n";

    return 0;
}

输出如下

normal construct
A's class id is 1 A's data is 2
B's class id is 1 B's data is 2

在构造函数中使用=delete

我们前面说的拷贝构造假如我们在默认的构造函数中使用=delete代表什么呢?代表我们进制默认构造发生,为什么?因为我们不想造成未定义表达式,所以要显示的给构造函数加上=delete,告诉用户在实例化的时候必须要初始化class,有的编译器我们不对默认构造函数加上=delete,并且没有写构造函数的时候,在实例化的时候会报错,有的编译器不会报错,所以我们要显示的定义必须初始化,不能不初始化

#include <iostream>

using namespace std;

class A{
public:    
    A() = delete;  //告诉编译器必须要初始化,不能使用默认初始化
    
    A(int data)
    :data_(data){
        cout << "initialized!" << endl;
    }
    
    int returndata_(void);
private:
    int data_;
};

int
A::returndata_(void){
    return data_;
}

int main()
{
    A a(1);
    A b; //这里会报错
    cout << "a's data is " << a.returndata_() << endl;
    //cout << "b's data is " << b.returndata_() << endl;
    //cout<<"Hello World";

    return 0;
}

当然我们也可以把=delete改成=default意思是显示的允许默认构造函数的出现,这样我们如果没有初始化,将会分配给我们一个默认的构造函数,data_会被初始化为0,如下

#include <iostream>

using namespace std;

class A{
public:    
    A() = default;
    
    A(int data)
    :data_(data){
        cout << "initialized!" << endl;
    }
    
    int returndata_(void);
private:
    int data_;
};

int
A::returndata_(void){
    return data_;
}

int main()
{
    A a(1);
    A b;
    cout << "a's data is " << a.returndata_() << endl;
    cout << "b's data is " << b.returndata_() << endl;  // data_被默认构造函数初始化为0
    //cout<<"Hello World";

    return 0;
}

总结

我们在写cpp的时候业务工程比较复杂,class比较多,也许会出现一个class包含另一个class的情况,比如class A里面包含了另一个class B,此时我们又正好对class A做操作,这个操作又正好隐式的引发拷贝构造,又恰好class A没有定义拷贝构造,编译器给他搞了一个默认的拷贝构造函数,默认拷贝构造函数尝试拷贝class A的所有变量给其他的class,包括class A中的成员class B(拷贝过程中会隐式的引发class B的拷贝构造),又恰好class A中的成员class B禁止拷贝构造B(const B&)=delete;此时就会报出如下的错误

/usr/include/c++/9/ext/new_allocator.h:145:20: error: use of deleted function ‘B::B(const B&)
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数 "= delete" 是一个C++11中的新特性,允许将拷贝构造函数定义为删除的函数。当某个类的拷贝构造函数被定义为 "= delete" 时,意味着该类对象不能被拷贝构造。这种情况可能会发生在以下两种情况下: 1)某个数据成员的拷贝构造函数是删除的或不可访问的(private),则这个类的合成拷贝构造函数会被编译器定义为 delete 。 2)在C++11中,我们可以使用 "= delete" 在函数参数列表后来定义一个删除的函数。当我们将拷贝构造函数定义为 "= delete",这意味着我们明确地告诉编译器不允许发生类对象之间的拷贝构造。这种方式可以实现类对象之间的非拷贝语义。 需要注意的是,如果一个类的拷贝构造函数被定义为 "= delete",则该类的对象不能被拷贝构造,任何尝试对该对象进行拷贝构造的操作都会导致编译错误。这在一些特定的应用场景下是很有用的,比如单例模式等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [c++11 =delete的使用](https://blog.csdn.net/qq_43247439/article/details/107313642)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [C++11标准中的 deleted 函数](https://blog.csdn.net/weixin_41986518/article/details/87622907)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值