I am using the default constructor as an example here, but the same question applies to all the special member functions.
Also, I am using https://en.cppreference.com instead of the standard because that is what I am reading and that is what I am having trouble understanding. If using the standard would change the question in any way, please let me know.
As stated in https://en.cppreference.com/w/cpp/language/default_constructor, if a class has no constructor then the compiler will always declare a default one. Then, if certain conditions aren't met, it will be undefined (pre c++11) or defined as deleted (post c++11).
All this seems to imply that there is a difference between a function being not declared, declared but not defined, or declared and deleted. However, all three options won't compile/link, e.g.
class MyClass {
public:
void foo();
void bar() = delete;
};
int main() {
MyClass c;
//c.foo(); // won't link
//c.bar(); // won't compile
//c.baz(); // won't compile
}
So why is it so important to change the definition from "declared and undefined" to "declared and deleted", and why not just leave it as "undeclared" in the first place?
So why is it so important to change the definition from "declared and undefined" to "declared and deleted"
Because of the difference: "won't link" vs "won't compile". This is a fundamental reason for why = delete was introduced: To catch the bugs of using (previously) undefined functions at compile time, rather than later. Furthermore, it allows better error diagnostic, since the compiler will be able to describe why the function is deleted. The best that the linker can say is that nobody defined it for some unknown reason.
There's no reason not to take advantage of the feature with the implicitly generated member functions.
The = deleted; declaration can be useful in various situations. As well as the very good reason given by eerorika, it can also be used to explicitly declare that a given 'special' function, such as the default constructor doesn't exist, and cannot be called.
It can also be used to specify that a function which exists in a base class does not exist in a derived class (which, by default, it will).
Here's a short piece of code showing such usage:
#include <iostream>
class foo {
private:
int m;
public:
foo() = delete; // Other programmers reading this definition will know immediately!
foo(int n) : m{ n } {} // ... that default ctor is intended not to be used
void inc() { ++m; } // ... rather than it has been omitted accidentally
int get() { return m; }
};
class bar : public foo {
public:
bar() : foo(0) {}
void inc() = delete; // Without this, code like `bar b; b.inc();` will call foo.inc()
};
int main() {
// foo f1; // error C2280: 'foo::foo(void)': attempting to reference a deleted function
foo f2(3); std::cout << f2.get() << std::endl;
f2.inc(); std::cout << f2.get() << std::endl;
bar b1; std::cout << b1.get() << std::endl;
// b1.inc(); error C2280: 'void bar::inc(void)': attempting to reference a deleted function
return 0;
}
Related
This example fails to compile unless I uncomment the default constructor declaration:
#include<unordered_map>
#include <iostream>
struct foo{
int data;
/*foo(){
data = 0;
std::cout << "DEFAULT\n";
}*/
foo(int d){
data = d;
std::cout << "PARAM\n";
}
};
struct bar{
std::unordered_map<int, foo> map;
foo getElem(int i){
return map[i];
}
};
int main() {
bar b;
foo f1(1);
foo f2(2);
b.map.insert({1,f1});
b.map.insert({2,f2});
foo f3 = b.getElem(1);
}
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/tuple:1689:70: error: no matching function for call to 'foo::foo()'
1689 | second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
| ^
When I uncomment the default constructor declaration and successfully compile, the breadcrumbs show that the default constructor is not ever called.
What is going on here? A similar problem is due to a most vexing parse, but without any explicit constructor calls I am not sure if that is the case here.
This answer provides hints as to why an unordered_map would implicitly call a default constructor. Is the issue some combination of the documented behavior described and MVP?
link to godbolt
When the compiler compiles this line:
foo f3 = b.getElem(1);
1 is passed as a parameter to a function (unless a whole lot of optimization magic occured, which is not guaranteed). This function cannot know that 1 will never be a missing key. As such, the code that allocates an entry in the map is called. And what is passed to this code, if the key is missing ? Yep, a default-constructed foo.
So, in a nutshell, you know that
the default constructor is not ever called
but the compiler and linker don't.
The following is a perfectly legal C++ code
void foo (int) {
cout << "Yo!" << endl;
}
int main (int argc, char const *argv[]) {
foo(5);
return 0;
}
I wonder, if there a value to ever leave unnamed parameters in functions, given the fact that they can't be referenced from within the function.
Why is this legal to begin with?
Yes, this is legal. This is useful for implementations of virtuals from the base class in implementations that do not intend on using the corresponding parameter: you must declare the parameter to match the signature of the virtual function in the base class, but you are not planning to use it, so you do not specify the name.
The other common case is when you provide a callback to some library, and you must conform to a signature that the library has established (thanks, Aasmund Eldhuset for bringing this up).
There is also a special case for defining your own post-increment and post-decrement operators: they must have a signature with an int parameter, but that parameter is always unused. This convention is bordering on a hack in the language design, though.
Of course not naming a parameter is legal when just declaring the function, but it's also legal in the implementation. This last apparently strange version is useful when the function needs to declare the parameter to have a specific fixed signature, but the parameter is not needed.
This may happen for example for a method in a derived class, for a callback function or for a template parameter.
Not giving the parameter a name makes clear that the parameter is not needed and its value will not be used. Some compilers if you instead name a parameter and then simply don't use it will emit a warning that possibly there is a problem with the function body.
Just wanted to mention a specific (unusual but interesting) usecase - the "passkey idiom".
It uses a "dummy" parameter of a type, constructor of which is accessible only to its friends. Its purpose is only to check, whether the caller has access to this constructor. So it needs no name as it is not used in the function, only the compiler uses it.
It's used like this:
class Friendly; // Just a forward declaration
class Key {
private:
Key() {}
friend class Friendly;
};
class Safe() {
public:
static int locked(Key, int i) {
// Do something with `i`,
// but the key is never used.
return i;
}
private:
static void inaccessible() {}
};
class Friendly {
public:
void foo() {
int i = Safe::locked(Key(), 1); // OK
int j = Safe::locked({}, 2); // OK, sice C++11
}
void bar() {
Safe::inaccessible(); // Not OK, its inaccessible
}
};
int i = Safe::locked(3); // Not OK, wrong parameters
int j = Safe::locked(Key(), 4); // Not OK, `Key` constructor is inaccessible
int k = Safe::locked({}, 5); // Not OK, `{}` means `Key()` implicitly
I just want to add that there is sometimes a difference whether you name a parameter or not. For example, the compiler treats a named rvalue reference as an lvalue and an unnamed rvalue reference as an rvalue.
// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return block;
}
int main()
{
g(f(MemoryBlock()));
}
This example produces the following output:
In g(const MemoryBlock&).
In g(MemoryBlock&&).
In this example, the main function passes an rvalue to f. The body of f treats its named parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference (the first overloaded version of g).
The following is a perfectly legal C++ code
void foo (int) {
cout << "Yo!" << endl;
}
int main (int argc, char const *argv[]) {
foo(5);
return 0;
}
I wonder, if there a value to ever leave unnamed parameters in functions, given the fact that they can't be referenced from within the function.
Why is this legal to begin with?
Yes, this is legal. This is useful for implementations of virtuals from the base class in implementations that do not intend on using the corresponding parameter: you must declare the parameter to match the signature of the virtual function in the base class, but you are not planning to use it, so you do not specify the name.
The other common case is when you provide a callback to some library, and you must conform to a signature that the library has established (thanks, Aasmund Eldhuset for bringing this up).
There is also a special case for defining your own post-increment and post-decrement operators: they must have a signature with an int parameter, but that parameter is always unused. This convention is bordering on a hack in the language design, though.
Of course not naming a parameter is legal when just declaring the function, but it's also legal in the implementation. This last apparently strange version is useful when the function needs to declare the parameter to have a specific fixed signature, but the parameter is not needed.
This may happen for example for a method in a derived class, for a callback function or for a template parameter.
Not giving the parameter a name makes clear that the parameter is not needed and its value will not be used. Some compilers if you instead name a parameter and then simply don't use it will emit a warning that possibly there is a problem with the function body.
Just wanted to mention a specific (unusual but interesting) usecase - the "passkey idiom".
It uses a "dummy" parameter of a type, constructor of which is accessible only to its friends. Its purpose is only to check, whether the caller has access to this constructor. So it needs no name as it is not used in the function, only the compiler uses it.
It's used like this:
class Friendly; // Just a forward declaration
class Key {
private:
Key() {}
friend class Friendly;
};
class Safe() {
public:
static int locked(Key, int i) {
// Do something with `i`,
// but the key is never used.
return i;
}
private:
static void inaccessible() {}
};
class Friendly {
public:
void foo() {
int i = Safe::locked(Key(), 1); // OK
int j = Safe::locked({}, 2); // OK, sice C++11
}
void bar() {
Safe::inaccessible(); // Not OK, its inaccessible
}
};
int i = Safe::locked(3); // Not OK, wrong parameters
int j = Safe::locked(Key(), 4); // Not OK, `Key` constructor is inaccessible
int k = Safe::locked({}, 5); // Not OK, `{}` means `Key()` implicitly
I just want to add that there is sometimes a difference whether you name a parameter or not. For example, the compiler treats a named rvalue reference as an lvalue and an unnamed rvalue reference as an rvalue.
// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return block;
}
int main()
{
g(f(MemoryBlock()));
}
This example produces the following output:
In g(const MemoryBlock&).
In g(MemoryBlock&&).
In this example, the main function passes an rvalue to f. The body of f treats its named parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference (the first overloaded version of g).
The following is a perfectly legal C++ code
void foo (int) {
cout << "Yo!" << endl;
}
int main (int argc, char const *argv[]) {
foo(5);
return 0;
}
I wonder, if there a value to ever leave unnamed parameters in functions, given the fact that they can't be referenced from within the function.
Why is this legal to begin with?
Yes, this is legal. This is useful for implementations of virtuals from the base class in implementations that do not intend on using the corresponding parameter: you must declare the parameter to match the signature of the virtual function in the base class, but you are not planning to use it, so you do not specify the name.
The other common case is when you provide a callback to some library, and you must conform to a signature that the library has established (thanks, Aasmund Eldhuset for bringing this up).
There is also a special case for defining your own post-increment and post-decrement operators: they must have a signature with an int parameter, but that parameter is always unused. This convention is bordering on a hack in the language design, though.
Of course not naming a parameter is legal when just declaring the function, but it's also legal in the implementation. This last apparently strange version is useful when the function needs to declare the parameter to have a specific fixed signature, but the parameter is not needed.
This may happen for example for a method in a derived class, for a callback function or for a template parameter.
Not giving the parameter a name makes clear that the parameter is not needed and its value will not be used. Some compilers if you instead name a parameter and then simply don't use it will emit a warning that possibly there is a problem with the function body.
Just wanted to mention a specific (unusual but interesting) usecase - the "passkey idiom".
It uses a "dummy" parameter of a type, constructor of which is accessible only to its friends. Its purpose is only to check, whether the caller has access to this constructor. So it needs no name as it is not used in the function, only the compiler uses it.
It's used like this:
class Friendly; // Just a forward declaration
class Key {
private:
Key() {}
friend class Friendly;
};
class Safe() {
public:
static int locked(Key, int i) {
// Do something with `i`,
// but the key is never used.
return i;
}
private:
static void inaccessible() {}
};
class Friendly {
public:
void foo() {
int i = Safe::locked(Key(), 1); // OK
int j = Safe::locked({}, 2); // OK, sice C++11
}
void bar() {
Safe::inaccessible(); // Not OK, its inaccessible
}
};
int i = Safe::locked(3); // Not OK, wrong parameters
int j = Safe::locked(Key(), 4); // Not OK, `Key` constructor is inaccessible
int k = Safe::locked({}, 5); // Not OK, `{}` means `Key()` implicitly
I just want to add that there is sometimes a difference whether you name a parameter or not. For example, the compiler treats a named rvalue reference as an lvalue and an unnamed rvalue reference as an rvalue.
// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return block;
}
int main()
{
g(f(MemoryBlock()));
}
This example produces the following output:
In g(const MemoryBlock&).
In g(MemoryBlock&&).
In this example, the main function passes an rvalue to f. The body of f treats its named parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference (the first overloaded version of g).
was struggling these days.
The problem is the constructor calling.
I wrote a piece of code like:
#include <iostream>
using namespace std;
class Foo
{
private: int _n;
public:
Foo() { Foo(5);}
Foo(int n) {_n=n; cout << n << endl; }
};
int main()
{
Foo* foo = new Foo();
return 0;
}
When I constructed a Foo object outside using the default constructor:
Foo* f = new Foo();
I suppose variable _n is 5, however, it's NOT.
It's ok in Java but NOT in c++.
In addition, in Visual C++ 6 sp 6,
Foo() {this->Foo(5);}
works.
However, this expression is refused by gcc/g++ 4.
Finally, I found out the solution.
Simply changing the default constructor into
Foo() {Foo(5);}
into
Foo() { new (this) Foo(5); }
solves the problem.
What does "this" in parentheses do?
What the (this) does, is creates a brand new Foo object, at the place pointed at by this (this is called placement new). You should only use it in arrays of char and unsigned char, nowhere else (and almost never there either). Since you are constructing a Foo at the location where this has already started construction, what you are doing is undefined behavior, and would leak resources all over the place if you had base classes. Historically, the normal thing to do is merely move the initialization to a private function.
class Foo {
public:
Foo() { init(5);}
Foo(int n) {init(n);}
private:
int _n;
void init(int n) {
_n=n;
};
}
In C++11 constructors should be able to call each other with this syntax, but I don't know which compilers support it yet. According to Apache, it's supported by GCC 4.7 and Clang 3.0, but not yet Intel C++ nor VC++.
class Foo {
public:
Foo() : Foo(5) {}
Foo(int n) {_n=n;}
private:
int _n;
}
The code you started with Foo() { Foo(5);} begins construction of this, then creates a brand new Foo object on the stack with the parameter 5, then destroys it, and then considers itself completely constructed, without initializing any of it's own values. That is why it compiled and ran, but didn't appear to do anything.
In C++11 you specify this with a delegating constructor:
Foo() : Foo(5) { }
The (this) in parenthesis means that the new operator will use the address of this as the address to initalize the class.
This is very dangerous: you're in the constructor of the current object, and you invoke a new constructor on the same memory space.
Just imagine what would happen if you inherit from another class!
As for your problem, you can't call another overloaded constructor from within the constructor.
The typical solution is to have a method to initialize your class:
class Foo
{
int _n;
public:
Foo() { init(5); }
Foo( int i) { init(i); }
void init(int i) { _n = i; }
};
I had quite the same problem here: Yet another C++ Object initialization interrogation ; feel free to look at the solution.
Foo() { new (this) Foo(5); }
is a "placement new" operator that calls a constructor on a pre-allocated memory.
Now, for you other question - C++11 allows exactly that (calling constructors from one another) but the earlier standard (especially the one used by MSVC 6) doesn't have that so the use of those ugly init() methods is the way to go for you.
The correct syntax in C++ is
class Foo {
private: int _n;
public:
Foo() : Foo(5) {}
Foo(int n) _n(n) {} // As suggested by another member's edit, initializer lists are preferred
};
Alternatively, C++ allows default parameter values, such as
Foo(int n = 5);
This allows you to write one constructor rather than two.
Also, you should be sure to learn about the difference between inline and non-inline functions. This Java-style of programming is valid C++, but it has it's pros and cons along with at least one other alternative.