C++11 ‘delete’ keyword and deleted functions

C++11 / C++14 : ‘delete’ keyword and deleted functions

本文将介绍C++11的一个新特性——delete,通过将delete应用到函数来限制其调用:

1
void someFunction() = delete ;

它通常用在以下的地方:

  • delete编译器生成的函数,如拷贝构造函数、赋值运算符、移动拷贝函数、移动赋值运算符和默认构造函数;
  • delete成员函数,以避免数据丢失;
  • delete类的new运算符,以限制堆的对象创建;
  • delete特定的模版特化;

Deleting Copy Constructor and Assignment Operator

假设存在这样的一个类,拷贝构造函数和赋值运算符都被delete了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class User
{

int id;
std::string name;
public:
User(int userId, std::string userName) : id(userId), name(userName)
{}

// Copy Constructor is deleted
User(const User & obj) = delete;
// Assignment operator is deleted
User & operator = (const User & obj) = delete;

void display()
{
std::cout<<id << " ::: "<<name<<std::endl;
}

};

如果调用这赋值运算符:

1
User obj = userObj;

编译时报错:

1
2
3
4
5
6
7
delete.cpp:30:10: error: call to deleted constructor of 'User'
User obj = userObj;
^ ~~~~~~~
delete.cpp:15:2: note: 'User' has been explicitly marked deleted here
User(const User & obj) = delete;
^
1 error generated.

Deleting member functions to prevent data loss conversions

由于类型的隐式转换,有可能会在调用函数时传递了错误的参数,例如:

1
2
3
4
5
6
7
User(int userId, std::string userName) : id(userId), name(userName){}


// 这样调用会被cast
User obj4(5.5, "Riti");

User obj5('a', "Riti");

通过利用delete来避免类型转换:

1
2
3
4
5
// Deleting a constructor that accepts a double as ID to prevent narrowing conversion
User(double userId, std::string userName) = delete ;

// Deleting a constructor that accepts a double as ID to prevent invalid type conversion
User(char userId, std::string userName) = delete ;

报错如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
elete.cpp:32:10: error: call to deleted constructor of 'User'
User userObj1(5.5, "John");
^ ~~~~~~~~~~~
delete.cpp:14:5: note: 'User' has been explicitly marked deleted here
User(double userId, std::string userName) = delete ;
^
delete.cpp:33:10: error: call to deleted constructor of 'User'
User userObj2('a', "John");
^ ~~~~~~~~~~~
delete.cpp:15:5: note: 'User' has been explicitly marked deleted here
User(char userId, std::string userName) = delete ;
^
2 errors generated.

Restrict Object creation on Heap by deleting new operator for class

我们也可以限制new运算符的使用:

1
2
3
4
void * operator new (size_t) = delete;

// 调用
User * ptr = new User(1, "Riti");

报错如下:

1
2
3
4
5
6
7
delete.cpp:34:17: error: call to deleted function 'operator new'
User *ptr = new User(1, "Rziti");
^
delete.cpp:17:12: note: candidate function has been explicitly deleted
void * operator new (size_t) = delete;
^
1 error generated.

Delete specific template specialisation

使用delete关键字,我们可以限制模板类或函数的某些模板特化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename T>
class ComplexNumber
{
T x;
T y;
public:
ComplexNumber(T a, T b) : x(a) , y(b)
{}
void display()
{
std::cout<<x << " + i"<<y<<std::endl;
}
// Deleted template specialisation
ComplexNumber(char a, char b) = delete;
// Deleted template specialisation
ComplexNumber(double a, double b) = delete;
};

原来该模版类可以接收char参数和double参数,通过delete,我们可以限制其特化。

Different between deleted function and private functions

相比private成员函数,delete有两个优点:

  • 避免被其它成员函数调用;
  • delete函数在name lookup中,如果函数delete了,那么它就不会根据该类型去查找其它匹配函数;