Meaning of = delete after function declaration
Deleting a function is a C++11 feature:
The common idiom of "prohibiting copying" can now be expressed
directly:class X {
// ...
X& operator=(const X&) = delete; // Disallow copying
X(const X&) = delete;
};
[...]
The "delete" mechanism can be used for any function. For example, we
can eliminate an undesired conversion like this:struct Z {
// ...
Z(long long); // can initialize with a long long
Z(long) = delete; // but not anything less
};
delete modifier vs declaring function as private
One difference is that =delete
allows for compile-time errors while in some cases the declaration without a definition is only caught at link-time (at which the error message is typically not pointing you to the source of the problem). One such case is when you add a member function that tries to copy an instance of A
. Even when it's not a member function of A
, the error message about the copy-ctor being private
is not as clear as using =delete
.
To avoid confusion, I'd recommend you make the deleted function public
as otherwise you will get additional and misleading error messages.
What does default mean after a class' function declaration?
It's a new C++11 feature.
It means that you want to use the compiler-generated version of that function, so you don't need to specify a body.
You can also use = delete
to specify that you don't want the compiler to generate that function automatically.
With the introduction of move constructors and move assignment operators, the rules for when automatic versions of constructors, destructors and assignment operators are generated has become quite complex. Using = default
and = delete
makes things easier as you don't need to remember the rules: you just say what you want to happen.
What's the exact semantics of deleted member functions in C++11?
a = A(); // error C2280
The expression on the right is a temporary which means it will look for operator=(A&&)
and sees it is deleted. Hence the error. There is no further search.
=delete
does not mean "don't use me, instead use next best one". It rather means, "don't use me when you need me — instead be alone in the wild."
Here is another example. If I want the instances of my class X
to be created with only long
and no other type (even if it converts into long!), then I would declare class X
as:
struct X
{
X(long arg); //ONLY long - NO int, short, char, double, etc!
template<typename T>
X(T) = delete;
};
X a(1); //error - 1 is int
X b(1L); //ok - 1L is long
That means, the overload resolution is performed before the compiler sees the =delete
part — and thus results in an error because the selected overload is found deleted.
Hope that helps.
Warning when an explicitly defaulted function declaration is deleted
What you need to do is move the definition of the default member out of the class:
class NotMoveA
{
public:
NotMoveA() = default;
~NotMoveA() = default;
NotMoveA(const NotMoveA &) = delete;
NotMoveA(NotMoveA &&other) = default;
NotMoveA &operator=(const NotMoveA &) = delete;
//will B deleted w/o warning:
NotMoveA &operator=(NotMoveA &&other);
// ...
private:
const std::string badDataMemberDisallowingMoveAssignment;
// ...
};
NotMoveA & NotMoveA::operator=(NotMoveA &&other) = default;
Once you make it an out of line definition then you will get a compiler error as you cannot define the member function via = default
if it would be deleted:
error: defaulting this move assignment operator would delete it after
its first
declaration NotMoveA & NotMoveA::operator=(NotMoveA &&other) = default;
Declaring a function as defaulted after its first declaration
Suppose you have
// A.h
struct A {
A();
};
and
// A.cc
A::A() { }
You can change it to
// A.cc
A::A() = default;
to not force code using A.h
to be recompiled.
For a default constructor, this doesn't make much sense. = default
takes up more characters than { }
. But think of other constructor types: a copy or move constructor may become much shorter if it is no longer necessary to explicitly mention each field, and depending on the compiler and type you're dealing with, the defaulted copy/move constructor may even perform better, for example if the compiler can only detect that a memcpy
call will suffice when you use the = default
syntax.
error: use of deleted function
The error message clearly says that the default constructor has been deleted implicitly. It even says why: the class contains a non-static, const variable, which would not be initialized by the default ctor.
class X {
const int x;
};
Since X::x
is const
, it must be initialized -- but a default ctor wouldn't normally initialize it (because it's a POD type). Therefore, to get a default ctor, you need to define one yourself (and it must initialize x
). You can get the same kind of situation with a member that's a reference:
class X {
whatever &x;
};
It's probably worth noting that both of these will also disable implicit creation of an assignment operator as well, for essentially the same reason. The implicit assignment operator normally does members-wise assignment, but with a const member or reference member, it can't do that because the member can't be assigned. To make assignment work, you need to write your own assignment operator.
This is why a const
member should typically be static -- when you do an assignment, you can't assign the const member anyway. In a typical case all your instances are going to have the same value so they might as well share access to a single variable instead of having lots of copies of a variable that will all have the same value.
It is possible, of course, to create instances with different values though -- you (for example) pass a value when you create the object, so two different objects can have two different values. If, however, you try to do something like swapping them, the const member will retain its original value instead of being swapped.
Why were parentheses disambiguated as a function declaration with std::istream_iterator?
This line
deque<string> q(std::istream_iterator<string>(ss),
std::istream_iterator<string>());
is a function declaration with the return type deque<string>
and two parameters of the type std::istream_iterator<string>
. The first parameter has the name ss and the second parameter is unnamed.
To make this line a declaration of the variable q you should write either
deque<string> q( ( std::istream_iterator<string>(ss) ),
( std::istream_iterator<string>() ) );
or
deque<string> q(std::istream_iterator<string>{ ss },
std::istream_iterator<string>{});
In this case there are used expressions instead of parameter declarations.
You may include declarators in parentheses. For example
int ( x );
When a declaration is a parameter declaration then you may omit a declarator like
int()
Here is an example of three declarations of the same function.
int f( int( x ) );
int f( int x );
int f( int( x ) )
{
return 2 * x;
}
Related Topics
How to Get the Ip Address of a Local Computer
Std::Thread Pass by Reference Calls Copy Constructor
Best Compiler Warning Level For C/C++ Compilers
Embed Text File in a Resource in a Native Windows Application
Returning Arrays from a Function in C++
How to Start a Cuda App in Visual Studio 2010
Generate Random Double Numbers in C++
Strict Aliasing Rule and 'Char *' Pointers
Winmain and Main() in C++ (Extended)
Msvc++ Variadic Macro Expansion
String Literal Address Across Translation Units
C++ Custom Stream Manipulator That Changes Next Item on Stream