need to define all available constructor forms in c++ - c++

I have a class like this:
class A{
private:
init(const std::string& s=""){/*do something*/}
public:
A(){init();}
A(const A&){init();}
A(const std::string& s){init(s);}
};
Does it cover all the forms that constructors may be called?
What I am trying to do is, any object creation must call the init() function at first i.e I need to define all the constructors that may be called implicitly or explicitly.

A(const A&)
once you have defined A(A const&) the compiler will not synthesize any other constructors. The only callable constructors will be the ones you declare.
The same is true of A(A&&), as an aside.

It sounds like you have a slight misunderstanding of C++ constructors.
Under specific circumstances classes have certain constructors implicitly declared with defaulted definitions. To avoid constructors that don't call your init() function does not require you to declare these constructors. You can instead follow certain rules that prevent them from being implicitly declared, or you can define some in-class initialization which ensures that the default definitions do the extra initialization you want.
The default constructor is only implicitly declared as defaulted if there are no user-declared constructors.
A copy constructor is only implicitly declared as defaulted if there are no user-declared move constructors or move-assignment operators (and of course no user-declared copy constructor).
A move constructor is only implicitly declared if there are no user-declared copy constructors, copy assignment operators, move constructors, move assignment operators, or destructors (and if the default definition for a move constructor would be valid).
So you could ensure that object construction always calls your init() function by declaring some subset of members that suppresses implicit declarations of any other constructors.
(This slideshow has a handy reference on the conditions for implicit declarations of the special member functions.)
Following the above rules: Declaring this copy constructor, for example, suppresses the default constructor, the move constructor, and the implicitly declared copy constructor. This therefore ensures that no objects of this class can be constructed without calling the init() member function.
struct S {
S(S const &) { init(); }
void init() {}
};
You can also simply use C++11 in-class initialization, which executes even in default definitions, to ensure init() is called for all construction.
struct S {
int x = init();
int init() { return 10; }
// ... whatever constructors you want to define
};
So long as your user-declared constructors don't explicitly initialize x, then all the constructors, both user-declared and implicitly declared, will call init().

I have a hack that does this, but it isn't the most clear on intent.
class A{
private:
bool init(...){...; return true; }
bool initialized = init(...);
public:
// your constructors.
};
Do keep in mind that the parameters to init have not to be dependent on the parameters of the constructor.

For this case, it might be worth considering using implementation inheritance:
class base {
protected:
base(std::string const &s="") { /* equivalent of your `init` */ }
// Or possibly use overloading:
// base() { /* whatever */ }
// base(std::string const &) { /* whatever */ }
};
class A : public base {
A(const std::string& s) : base(s) {}
A(const A&, const std::string& s) : base(s) {}
};
Since A is derived from base, every ctor for A must invoke base's constructor. If you don't use the member initializer list to pass a parameter, it'll be invoked automatically with the default parameter--but creating an A without invoking the base ctor is essentially impossible.

I think you'd better define the move constructor A(A&&), I'm not sure about the policies on automatically generate constructor of different compilers, though C++11 has the explicit definition.
see more info here

Related

Do I need to respect the rule of five here?

So on https://en.cppreference.com/w/cpp/language/rule_of_three it says:
Because the presence of a user-defined (or = default or = delete declared) destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator, any class for which move semantics are desirable, has to declare all five special member functions
So for this class I've done the following
#include <string>
#include <iostream>
class Data {
private:
std::string m_name;
public:
Data() { m_name = "stackman"; }
~Data() = default;
Data(const Data&) = delete;
Data& operator=(const Data&) = delete;
Data(Data&&) = delete;
Data& operator=(Data&&) = delete;
std::string get_name() { return m_name; }
};
int main()
{
Data person;
std::cout << person.get_name() << std::endl;
}
I've seen conflicting resources online saying that if the destructor is set to default and if you don't need the other constructors you don't need to delete or define them. So what's the best course of action here?
If you intend to default the destructor and you do not intend to make the class non-movable or non-copyable explicitly, then you should not declare the destructor at all. There is no benefit to doing that. Follow the rule-of-zero and don't declare any of the special member functions at all.
In some circumstances you need to default the destructor explicitly, specifically if you want to declare it as virtual, but otherwise leave it to behave like the implicit destructor. The issue with that is that this disables the implicit declaration of the move operations. So you should, again assuming that you do not want to intentionally disable move or copy operations, explicitly default all of the special member functions. They will still be defined as deleted if the default implementation wouldn't work. This is also in line with the rule-of-five which you quoted.
If you do this in a non-template class the compiler might warn you about the default member function being deleted if that happens. In that case you can remove or delete the offending member function to silence the warning.
If you do intend to explicitly make the class non-copyable or non-movable, then delete the relevant special member functions and default the rest.

Default constructor of an Empty Class is public. But how?

I have a simple question:
class my
{
};
my ob;
Compiler allows me to create an object which makes sense. And, I am aware that you can't create object where the constructor is private.
To me it looks that, everything inside the class is private but obviously not the default constructor(because it is allowing me to create the object as default constructor should be public). But what confuses me is that there is no public section in the class.
So, does it create a public section only to put a default constructor under it in this case?
Or there is something else going on and my rationale is incorrect?
Also, how are accesses public, private and protected internally organised/tracked when an object is created/accessed?
I got this question as I never created an object of an empty class until now.
If you do not declare any constructor yourself, C++ compilers will always generate a public trivial constructor for you. More than that even, it will also implicitly create a public copy constructor and assignment operator.
From C++11 standard 12.1.5:
If
there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted. An implicitly-declared default constructor is an inline public member of its class.
and 12.8.7, 12.8.11:
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. [...] An implicitly-declared copy [...] constructor is an inline public member of its class.
and finally 12.8.18, 12.8.20, 12.8.22:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. [...] If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly
declared [...]. An implicitly-declared
copy/move assignment operator is an inline public member of its class.
Note that a move assignment operator will only be generated under certain circumstances, which are beyond the scope of this question, see 12.8.20 for more details.
If you want a private constructor you have to declare it yourself:
class my { my() {} };
If you want to prevent the generation of copy constructor or assignment operator you can either declare, but not implement them:
class my { my(my const &); };
Or, since C++11, explicitly delete them:
class my { my(my const &) = delete; };
Yes, the compiler will produce the default constructor and the default copy constructor and default assignment operators as "public" - because anything else would make the class rather useless...
Of course, those constructors would be rather simple - in fact, it can be replaced with "nothing", since constructing an empty class will do nothing.
The compiler generated default constructor (and other operators) are automatically public. If you want the default constructor to be private then you need to specify this yourself my declaring it within a private section of your class.
The concepts of private, protected and public are only relevant to the compiler. They have no meaning and are not tracked at runtime.
The compiler will generate the default constructor as inline public if it is not defined by the user, the relevant section of the C++ draft standard is 12.1/5:
If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class.
Usually compiler by default generates 4 things at the time of creation of object.
Default constructor
Copy constructor
Copy assignment operator
Destructor
For example:
class First {
First(){} //default constructor
First(const First &){} //copy constructor
First& operator=(const First&){ //Copy assignment operator
return *this;
}
~First(){} //Destructor
}
These are implicitly inline public member, unless there is no user declared constructor.

Can I make the copy constructor private and still use the default implementation

I think this impossible but I might as well ask.
Can I declare a private Copy-Constructor and still use the default implementation?
Background: I have a class with very big vectors and I do not want to call the copy constructor except for one member function. Using a standard public copy-ctor might
easily lead to bugs like e.g. forgetting a reference in an iteration (foreach(Type el,vectOfBigObjects) instead of foreach(Type const& el,vectOfBigObjects)). Hence I want to keep the standard copy consructor but just make it private.
Is this possible without rewriting the copy-ctors definition ?
Is this possible without rewriting the copy-ctors definition ?
In C++11, yes. You just have to declare the constructor and mark it as defaulted:
struct X
{
// ...
private:
X(X const&) = default;
};
This will define a copy constructor which would have the same definition as an implicitly generated one, but will be private. For instance:
struct X
{
X() { } // Required because a user-declared constructor in
// the definition of X inhibits the implicit generation
// of a default constructor (even if the definition is
// defaulted!)
void foo()
{
// ...
X tmp = *this; // OK!
// ...
}
private:
X(X const&) = default; // Default definition, accessible to
// member functions of X only!
};
int main()
{
X x;
// X x2 = x; // ERROR if uncommented!
}
Here is a live example.
Notice, that a user-declared constructor (including copy constructor) in a class definition inhibits the implicit generation of a default constructor, even if its definition is defaulted. This is why, for instance, I had to explicitly declare X's default constructor in the example above.

What are defaulted methods and how do I use them properly? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the point in defaulting functions in C++11?
C++11 introduced defaulted methods (e.g. void myMethod() = default;).
What does it do to methods (how do methods behave after being defaulted). How do I use them properly (what are its uses)?
There are a number of class members that are considered "special member functions" by the C++ standard. These are:
The default constructor (a constructor that can be called with no parameters).
The copy constructor (a constructor that can be called with one parameter that is the object type as an lvalue reference).
The copy assignment operator (an operator= overload that can be called with one parameter that is the object type as either an lvalue reference or a value).
The move constructor (a constructor that can be called with one parameter that is the object type as an rvalue reference).
The move assignment operator (an operator= overload that can be called with one parameter that is the object type as either an rvalue reference or a value).
The destructor.
These member functions are special in that the language does special things with them on types. Another thing that makes them special is that the compiler can provide definitions for them if you do not. These are the only functions that you can use the = default; syntax on.
The issue is that the compiler will only provide a definition under certain conditions. That is, there are conditions under which a definition will not be provided.
I won't go over the entire list, but one example is what others have mentioned. If you provide a constructor for a type that is not a special constructor (ie: not one of the constructors mentioned above), a default constructor will not be automatically generated. Therefore, this type:
struct NoDefault
{
NoDefault(float f);
};
NoDefault cannot be default constructed. Therefore, it cannot be used in any context where default construction is needed. You can't do NoDefault() to create a temporary. You can't create arrays of NoDefault (since those are default constructed). You cannot create a std::vector<NoDefault> and call the sizing constructor without providing a value to copy from, or any other operation that requires that the type be DefaultConstructible.
However, you could do this:
struct UserDefault
{
UserDefault() {}
UserDefault(float f);
};
That would fix everything, right?
WRONG!
That is not the same thing as this:
struct StdDefault
{
StdDefault() = default;
StdDefault(float f);
};
Why? Because StdDefault is a trivial type. What does that mean? I won't explain the whole thing, but go here for the details. Making types trivial is often a useful feature to have, when you can do it.
One of the requirements of a trivial type is that it does not have a user-provided default constructor. UserDefault has a provided one, even though it does the exact same thing as the compiler-generated one would. Therefore, UserDefault is not trivial. StdDefault is a trivial type because = default syntax means that the compiler will generate it. So it's not user-provided.
The = default syntax tells the compiler, "generate this function anyway, even if you normally wouldn't." This is important to ensure that a class is a trivial type, since you cannot actually implement special members the way the compiler can. It allows you to force the compiler to generate the function even when it wouldn't.
This is very useful in many circumstances. For example:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
private:
std::unique_ptr<SomeType> m_ptr;
};
We must write every one of these functions to make the class copy the contents of the unique_ptr; there's no way to avoid that. But we also want this to be moveable, and the move constructor/assignment operators won't automatically be generated for us. It'd silly to re-implement them (and error-prone if we add more members), so we can use the = default syntax:
class UniqueThing
{
public:
UniqueThing() : m_ptr(new SomeType()) {}
UniqueThing(const UniqueThing &ptr) : m_ptr(new SomeType(*ptr)) {}
UniqueThing(UniqueThing &&ptr) = default;
UniqueThing &operator =(const UniqueThing &ptr)
{
m_ptr.reset(new SomeType(*ptr)); return *this;
}
UniqueThing &operator =(UniqueThing &&ptr) = default;
private:
std::unique_ptr<SomeType> m_ptr;
};
Actually, default can only apply to special methods - i.e. constructors, destructors, assignment operator:
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
1 A function definition of the form:
attribute-specifier-seqopt decl-specifier-seqopt declarator = default ;
is called an explicitly-defaulted definition. A function that is explicitly defaulted shall
— be a special member function,
— have the same declared function type (except for possibly differing ref-qualifiers and except that in
the case of a copy constructor or copy assignment operator, the parameter type may be “reference to
non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared,
and
— not have default arguments.
They behave the same as if the compiler generated them and are useful for cases like:
class Foo{
Foo(int) {}
};
here, the default constructor doesn't exist, so Foo f; wouldn't be valid. However, you can tell the compiler that you want a default constructor without the need to implement it yourself:
class Foo{
Foo() = default;
Foo(int) {}
};
EDIT: Pointed out by #Nicol Bolas in the comments, this truly doesn't explain why you'd prefer this over Foo() {}. What I'm guessing is: if you have a class w/ implementations separated in an implementation file, your class definition (if you don't use =default) would look like:
class Foo{
Foo();
Foo(int);
};
What I'm assuming is that the =default is meant to provide an idiomatic way of telling you "we're not doing anything special in the constructor". With the above class definition, the default constructor could very well not value-initialize the class members. With the =default you have that guarantee just by looking at the header.
Using = default on a constructor or copy-constructor means that the compiler will generate that function for you during compile-time. This happens normally when you exclude the respective functions from your class/struct. And in the case where you define your own constructor, this new syntax allows you to explicitly tell the compiler to default-construct the constructor where it normally won't. Take for instance:
struct S {
};
int main() {
S s1; // 1
S s2(s1); // 2
}
The compiler will generate both a copy-constructor and a default-constructor, thus allowing us to instantiate an S object like we did (1) and copy s2 into s1 (2). But if we define our own constructor, we find that we are unable to instantiate in the same way:
struct S {
S(int);
};
int main() {
S s; // illegal
S s(5); // legal
}
This fails because S has been given a custom-defined constructor, and the compiler won't generate the default one. But if we still want the compiler to give us one, we can explicitly convey this using default:
struct S {
S(int);
S() = default;
S(const S &) = default;
};
int main() {
S s; // legal
S s(5); // legal
S s2(s); // legal
}
Note, however, that only certain functions with certain function-signatures can be overloaded. It follows that this will fail because it is neither a copy-constructor nor a default-constructor or a move or assignment operator:
struct S {
S(int) = default; // error
};
We are also able to explicitly define the assignment operator (just like the default/copy-constructor, a default one is generated for us when we do not write out our own). So take for example:
struct S {
int operator=(int) {
// do our own stuff
}
};
int main() {
S s;
s = 4;
}
This compiles, but it won't work for us in the general case where we want to assign another S object into s. This is because since we wrote our own, the compiler doesn't provide one for us. This is where default comes into play:
struct S {
int operator=(int) {
// do our own stuff
}
S & operator=(const S &) = default;
};
int main() {
S s1, s2;
s1 = s2; // legal
}
But technically it's superfluous to define the assignment operator, copy, or move constructor as default when there is no other function "overriding" it as the compiler will provide one for you in that case anyway. The only case in which it won't provide you one is where you define your own one (or variation thereof). But as a matter of preference, asking the compiler to provide a default function using the new aforementioned syntax is more explicit and easier to see and understand if intentionally left out for the compiler.

Initialize object member with reference in initialization list

Am I doing this right? This is a highly simplified version of my code:
class Logger {
public:
Logger(std::ostream) { /*...*/}
};
class Driver {
public:
Driver() : m_logger(std::cout) {}
Driver(Logger& logger) : m_logger(logger) {}
private
Logger m_logger;
};
So my class Driver has a member of type Logger. When I call the argument-less constructor Driver(), the instance of Driver creates its own instance of Logger using std::cout.
When calling Driver(Logger) the instance shall use an already existing instance of Logger passed as a reference.
The above code compiles using g++. Although I understand what happens when calling Driver(), I don't get what happens when calling Driver(Logger). Logger has no constructor which accepts a reference on Logger as argument ("copy constructor"). So what is executed when calling Driver(Logger)?
A trivial copy constructor for Logger is synthesised for you, unless you declare one yourself.
This is much the same as how a trivial default constructor is synthesised for you (if you don't declare a default user-defined constructor).
[C++11: 12.8/7]: If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor
is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition
struct X {
X(const X&, int);
};
a copy constructor is implicitly-declared. If the user-declared constructor is later defined as
X::X(const X& x, int i =0) { /* ... */ }
then any use of X’s copy constructor is ill-formed because of the ambiguity; no diagnostic is required.
[C++11: 12.8/8]: The implicitly-declared copy constructor for a class X will have the form
X::X(const X&)
if
each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&.
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
When you construct a Driver with a Logger argument, it is taken by reference and the Logger copy constructor is invoked to initialize m_logger, so you end up with a new Logger that is a copy of the argument. The copy constructor is provided by the compiler unless you explicitly make Logger non-copyable, by declaring the copy constructor private.
Seems perfectly valid, except that you should make the logger argument a const reference; you're going to copy it, after all, not modify it.