How to Delete a Function in C++11 / 14?

In modern C++, the ‘delete’ keyword plays a crucial role in enhancing code safety and correctness. Introduced in C++11, this powerful feature allows programmers to explicitly forbid the use of certain functions, including automatically generated ones like default constructors and assignment operators. In this article, we will explore the practical applications of the ‘delete’ keyword and how it can be used.

Deleting Functions with the ‘delete’ Keyword

The ‘delete’ keyword can be applied to functions to make them uncallable, effectively preventing their use in a program. When a function is marked as deleted, any attempt to call it will result in a compile-time error. This is particularly useful for managing special member functions that the compiler might otherwise automatically generate.

Here’s a simple example of a function being deleted:

void someFunction() = delete;

Practical Use Cases for the ‘delete’ Keyword

The ‘delete’ keyword is particularly useful for:

  1. Deleting compiler-generated functions like copy constructors, assignment operators, move constructors, move assignment operators, and default constructors.
  2. Deleting member functions to prevent implicit type conversions that could lead to data loss.
  3. Restricting object creation on the heap by deleting the new operator for a class.
  4. Deleting specific template specializations.

Deleting Copy Constructors and Assignment Operators in C++

Consider a User class where you want to disable copy semantics:

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;
    }
};

In the above class User, the Copy Constructor and Assignment Operator are deleted. If anybody tries to call these deleted functions, it will generate a compile-time error.
For example,

User userObj(3, "John");
// Error: Use of deleted function 'User::User(const User&)'
User anotherUser = userObj;

Trying to copy an instance of User will result in a compile-time error:

delete_example.cpp: In function ‘int main()’:
delete_example.cpp:136:13: error: use of deleted function ‘User::User(const User&)’
  User obj = userObj;
             ^
delete_example.cpp:111:2: note: declared here
  User(const User & obj) = delete;

Apart from applying the delete keyword to compiler-generated functions, we can also apply it to other functions.

Deleting Member Functions in a class in C++

Implicit type conversions can be convenient but dangerous. They can lead to data loss or logical errors if types are converted unexpectedly. Deleting specific constructors can prevent these unwanted conversions. For example:

// A constructor that might lead to implicit conversions
User(int userId, std::string userName);

// Creating an object with potentially problematic conversions
User obj4(5.5, "Riti");  // double to int
User obj5('a', "Riti");   // char to int

To prevent these conversions, declare these constructors as deleted:

// Deleting constructors to prevent implicit conversions
User(double userId, std::string userName) = delete;
User(char userId, std::string userName) = delete;

Here we are deleting two constructors that could lead to implicit conversions:

  • The first one prevents creating a User object with a double as the ID, which could lead to a narrowing conversion if the double value has no exact int representation.
  • The second one prevents creating a User object with a char as the ID, which could be nonsensical if the char doesn’t represent an integer.

Now on creating User object with double and char will throw compile time error.

Restricting Object Creation on the Heap

To ensure that instances of a class are only created on the stack (not on the heap), you can delete the new operator:

class User {
    // ...
    // Delete the new operator to prevent heap allocation
    void* operator new(size_t) = delete;
};

This line ensures that the new operator cannot be used with the User class. As a result, the following code would trigger a compile-time error:

// Error: Use of deleted function 'static void* User::operator new(size_t)'
User* userPtr = new User(1, "Riti");

By deleting the new operator, you ensure that all User objects are automatically destroyed when they go out of scope, which can help manage resources more effectively and prevent memory leaks.

Deleting Specific Template Specializations

With the delete keyword, we can restrict certain template specializations of template classes or functions. Let’s see how to do that. Suppose we have a template class for a Complex Number.

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;
    }
};

We can use ComplexNumber with different types like int, double, and char, etc. For example,

ComplexNumber<int> obj1(1,2);

ComplexNumber<double> obj2(1.0,2.0);

ComplexNumber<char> obj3('1' , '2');

To restrict the usage of ComplexNumber with double or char as template parameters, we need to explicitly delete those specializations. For example:

ComplexNumber(char a, char b) = delete;

ComplexNumber(double a, double b) = delete;

Now, attempting to use the ComplexNumber<> class with double or char as the template parameter will generate a compile-time error.

The complete ComplexNumber class with the deleted specializations is as follows:

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;
};

Calling Following functions will result in error

// Error
ComplexNumber<double> obj2(1.0,2.0);

// Error
ComplexNumber<char> obj3('1' , '2');

Deleted Functions vs. Private Functions

While making functions private can also restrict their accessibility, deleted functions offer distinct advantages:

  • Private member functions can still be called by other members of the same class, while deleted functions cannot be called at all.
  • Deleted functions participate in name lookup. If a deleted function is found during compilation, the compiler does not continue to look for other overloads that might accept the arguments, preventing potential bugs and data loss.

Summary

The ‘delete’ keyword is a powerful feature in C++ that serves as a building block for safer and more maintainable code. By disabling certain functions or conversions, programmers can prevent a host of issues that could arise from inadvertent misuse. Use the ‘delete’ keyword to clearly communicate the intended use of your classes and functions, and to leverage the C++ type system for robust software development.

2 thoughts on “How to Delete a Function in C++11 / 14?”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top