How to make sure your object is zero-initialized? - c++11

Update: I'm looking to see if there's a way to zero-initialize the entire class at once, because technically, one can forget adding a '= 0' or '{}' after each member. One of the comments mentions that an explicitly defaulted no-arg c-tor will enable zero-initialization during value-initialization of the form MyClass c{};. Looking at http://en.cppreference.com/w/cpp/language/value_initialization I'm having trouble figuring out which of the statements specify this.
Initialization is a complex topic now since C++11 has changed meaning and syntax of various initialization constructs. I was unable to gather good enough info on it from other questions. But see, for example, Writing a Default Constructor Forces Zero-Initialization?.
The concrete problem I'm facing is: I want to make sure members of my classes are zeroed out both for (1) classes which declare a default c-tor, and for (2) those which don't.
For (2), initializing with {} does the job because it's the syntax for value-initialization, which translates to zero-initialization, or to aggregate initialization if your class is an aggregate - case in which members for which no initializer was provided (all!) are zero-initialized.
But for (1) I'm still not sure what would be the best approach. From all info I gather I learned that if you provide a default c-tor (e.g. for setting some of the members to some values), you must explicitly zero remaining members, otherwise the syntax MyClass c = MyClass(); or the C++11 MyClass c{}; will not do the job. In other words, value-initialization in this case means just calling your c-tor, and that's it (no zero-ing).
You run into the same situation if you declare a c-tor that takes values, and sets those values to a subset of the members, but you'd like other members to be zero-ed: there is no shorthand for doing it - I'm thinking about 3 options:
class MyClass
{
int a;
int b;
int c;
MyClass(int a)
{
this->a = a;
// now b and c have indeterminate values, what to do? (before setting 'a')
// option #1
*this = MyClass{}; // we lost the ability to do this since it requires default c-tor which is inhibited by declaring this c-tor; even if we declare one (private), it needs to explicitly zero members one-by-one
// option #2
std::memset(this, 0, sizeof(*this)); // ugly C call, only works for PODs (which require, among other things, a default c-tor defaulted on first declaration)
// option #3
// don't declare this c-tor, but instead use the "named constructor idiom"/factory below
}
static MyClass create(int a)
{
MyClass obj{}; // will zero-initialize since there are no c-tors
obj.a = a;
return obj;
}
};
Is my reasoning correct?
Which of the 3 options would you choose?

What about using in-class initialization?
class Foo
{
int _a{}; // zero-it
int _b{}; // zero-it
public:
Foo(int a): _a(a){} // over-rules the default in-class initialization
};

Option 4 and 5:
option 4:
MyClass(int a) :a(a), b(0), c(0)
{
}
option 5:
class MyClass
{
int a = 0;
int b = 0;
int c = 0;
MyClass(int a) : a(a) {
}
}

In my humble opinion, the simplest way to ensure zero-initialization is to add a layer of abstraction:
class MyClass
{
struct
{
int a;
int b;
int c;
} data{};
public:
MyClass(int a) : data{a} {}
};
Moving the data members into a struct lets us use value-initialization to perform zero-initialization. Of course, it is now a bit more cumbersome to access those data members: data.a instead of just a within MyClass.
A default constructor for MyClass will perform zero-initialization of data and all its members because of the braced-initializer for data. Additionally, we can use aggregate-initialization in the constructors of MyClass, which also value-initializes those data members which are not explicitly initialized.
The downside of the indirect access of the data members can be overcome by using inheritance instead of aggregation:
struct my_data
{
int a;
int b;
int c;
};
class MyClass : private my_data
{
MyClass() : my_data() {}
public:
MyClass(int a) : MyClass() { this->a = a; }
};
By explicitly specifying the base-initializer my_data(), value-initialization is invoked as well, leading to zero-initialization. This default constructor should probably be marked as constexpr and noexcept. Note that it is no longer trivial. We can use initialization instead of assignment by using aggregate-initialization or forwarding constructors:
class MyClass : private my_data
{
public:
MyClass(int a) : my_data{a} {}
};
You can also write a wrapper template that ensures zero-initialization, thought the benefit is disputable in this case:
template<typename T>
struct zero_init_helper : public T
{
zero_init_helper() : T() {}
};
struct my_data
{
int a;
int b;
int c;
};
class MyClass : private zero_init_helper<my_data>
{
public:
MyClass(int a) { this->a = a; }
};
Having a user-provided constructor, zero_init_helper no longer is an aggregate, hence we cannot use aggregate-initialization any more. To use initialization instead of assignment in the ctor of MyClass, we have to add a forwarding constructor:
template<typename T>
struct zero_init_helper : public T
{
zero_init_helper() : T() {}
template<typename... Args>
zero_init_helper(Args&&... args) : T{std::forward<Args>(args)...} {}
};
class MyClass : private zero_init_helper<my_data>
{
public:
MyClass(int a) : zero_init_helper(a) {}
};
Constraining the constructor template requires some is_brace_constructible trait, which is not part of the current C++ Standard. But this already is a ridiculously complicated solution to the problem.
It is also possible to implement your option #1 as follows:
class MyClass
{
int a;
int b;
int c;
MyClass() = default; // or public, if you like
public:
MyClass(int a)
{
*this = MyClass{}; // the explicitly defaulted default ctor
// makes value-init use zero-init
this->a = a;
}
};
What about constructor delegation?
class MyClass
{
int a;
int b;
int c;
MyClass() = default; // or public, if you like
public:
MyClass(int a) : MyClass() // ctor delegation
{
this->a = a;
}
};
[class.base.init]/7 suggests that the above example shall invoke value-initialization, which leads to zero-initialization since the class does not have any user-provided default constructors [dcl.init]/8.2. Recent versions of clang++ seem to zero-initialize the object, recent versions of g++ do not. I've reported this as g++ bug #65816.

Related

C++ friend member function behaviour looks erratic

I have always tried to avoid friend concept because it beats the purpose of encapsulation. However, I was just experimenting with the concept and the following code fails to compile with the following error:
main.cpp:29:28: error: ‘int A::a’ is private within this context
On the other hand, if I just place the class B before class A with forward declaration of class A, it runs fine. Am I missing something really trivial here?
#include <iostream>
class A {
int a;
public:
A() { a = 0; }
// friend function
friend void B::showA(A& x);
};
class B
{
public:
void showA(A&);
private:
int b;
};
void B::showA(A& x)
{
// Since showA() is a friend, it can access
// private members of A
std::cout << "A::a=" << x.a;
}
int main()
{
A a;
B b;
b.showA(a);
return 0;
}
As it is, you are using class B within class A, but as you can see B is not declared before it is used.
That is causing an error like this:
error: 'B' has not been declared
and a little further
error: int 'A::a' is private within this context
because the friendship relationship has not been linked due to the first error (as A::a is by default private)
You may try then to forward-declare B, like the following
#include<..>
class B;
class A {
int a;
public:
A() { a = 0; }
// friend function
friend void B::showA(A& x);
};
class B{
...
}
...
This would generate an error error: invalid use of incomplete type 'class B' because a forward declaration only says that a particular
class (here class B) will be defined later so you can reference it or have pointers to it, but it does not say what members this class
will have, so the compiler is unable to know if your future class Bwould have a B::showA method, thus the error, incomplete type error. At this time, the compiler does not know if your future class B (used in class A) would have a function B::showA.
The simplest solution would be to declare B before A and then forward declare A (with class A;) as follows. This way, you tell the compiler - here is my class B declaration (it contains a method B::showA),
and it uses a class A that I will define later. As there is no need to known what would be the content of A, it will compile.
// as you use class A before it is declared, you need to forward declare it
class A;
class B
{
public:
void showA(A&);
private:
int b;
};
class A {
int a;
...
This would compile and execute the function B::showA.

How to make a type alias depending on a compile-time constant within a class?

I want to write a class that makes use of numerical quadrature. The quadrature order defines the size of some containers that I will use. I would like to make a type alias for such containers and it has to depend on the quadrature order.
The following code shows my trials. It feels suboptimal in the sense that I have to repeat the order in the type alias definition:
#include <array>
class Quadrature
{
public:
static constexpr unsigned int getOrder()
{
return 3;
}
// This line doesn't compile!
//
// using WeightsContainer = std::array<double, getOrder()>;
//
// g++ says "error: 'static constexpr unsigned int Quadrature::getOrder()'
// called in a constant expression before its definition is complete"
// This line compiles, but repeats the order. :-(
using WeightsContainer = std::array<double, 3>;
private:
WeightsContainer container;
};
One solution that I have found is introducing a template parameter Order. But actually I wanted to determine the quadrature order and introducing the template parameter would make it variable.
Is there a possibility to make the order a compile-time constant and use it within my type alias definition?
Edit:
For completeness, I could of course use a preprocessor define. But that feels old-fashioned. :-)
Edit 2:
Okay, I have found another possibility. I could add a function outside the class scope like this:
constexpr unsigned int order()
{
return 3;
}
But that feels wrong, because this is a property of the class and therefore should be within class scope!
One thing you can do is to move the value into a member variable:
class Quadrature
{
private:
static constexpr unsigned int _order = 3;
public:
static constexpr unsigned int getOrder()
{
return _order;
}
using WeightsContainer = std::array<double, _order>;
// ...
};
If you need more complicated computations instead of just return 3, under C++17 you can use a lambda as #Quentin mentioned:
class Quadrature
{
public:
static constexpr auto getOrder = []()
{
return ...;
};
using WeightsContainer = std::array<double, getOrder()>;
// ...
};
Otherwise, you will need to pull the function outside of class scope for reasons mentioned here.

How to disable instantiating a temporary class?

I'm working with an expression template class which should not be instantiated to avoid dangling references. But I'm temped to declare a variable with auto and 'auto' create a named instance of a temporary class.
How can I disable auto declaration of temporary class in the following code?
class Base
{
};
class Temp : public Base
{
public:
Temp() {}
Temp(int, int) {}
Temp(const Temp&) = default;
Temp(Temp&&) = default;
};
Temp testFunc(int a, int b) {
return Temp{a,b};
}
int main() {
Base a = testFunc(1,2); // this should work
auto b = testFunc(1,2); // this should fail to compile
return 0;
}
You seem to want to prevent users from using auto on a particular type. That's not possible in any version of C++. If it is legal C++ for a user to write T t = <expr>;, where T is the type of <expr>, then it will be legal for a user to write auto t = <expr>; (ignoring class data members). Just as you cannot forbid someone from passing <expr> to a template function using template argument deduction.
Anything you do to prevent auto usage will also inhibit some other usage of the type.
One option would be to make Temp's constructors private, move testFunc inside the Temp class and make it static. This way you can still instantiate Base, but auto would fail because you would be calling a private constructor:
class Base
{
};
class Temp : public Base
{
Temp() {}
Temp(int, int) {}
Temp(const Temp&) = default;
Temp(Temp&&) = default;
public:
static Temp testFunc(int a, int b)
{
return Temp{a,b};
}
};
int main() {
Base a = Temp::testFunc(1,2); // this should work
auto b = Temp::testFunc(1,2); // this should fail to compile
return 0;
}
Demo

Forward declare unscoped enum in class complains private

Why does the following c++11/14 code not work? Here I am forward declaring an enum within the class. Objective is not to have a huge - 100s of values of enums within the class - which makes the class unreadable. I cannot use a separate scoped enum for this - for political reasons.
class A {
public:
// forward declare the enum
enum B : int;
void func (B b) {}
};
// The actual declaration
enum A::B : int {
Val1,
Val2,
};
int main ()
{
// B is unscoped. so I should be able to use it as below?
int a = A::Val1;
}
Compilation Error
tmp.cpp: In function ‘int main()’:
tmp.cpp:13:5: error: ‘A::B Val1’ is private
Val1,
^
tmp.cpp:19:16: error: within this context
int a = A::Val1;
^
But the following code works :
int a = A::B::Val1;
That error appears in G++ but not in Visual C++ and clang. Formally enum's id can be used as namespace, or can be skipped, but last two do skip it by default, while latest g++ enforces it. That's changeable by compiler options. Use of enum class' id is mandatory:
class A {
public:
// forward declare the enum
enum class B : int;
void func (B b) {}
};
// The actual declaration
enum class A::B : int {
Val1,
Val2,
};
int main ()
{
int a = static_cast<int>(A::B::Val1); // no implicit cast
}

C++11 move assignment operator for classes with objects as members - Beginner Level

I have a beginner question on the move assigment in c++11. Let say that I have a class A provided with a move assigment operator:
class A
{
public:
A();
~A();
A& operator=(A&&);
...
}
I also have a class B containing a class A object and provided with a move assignment operator
class B
{
public:
B();
~B();
B& operator=(B&&);
...
private:
A Test;
}
What I was thinking is that the B move assignment operator will call the move assignment operator of its member so I tried this method:
B& B::operator=(B&& Other)
{
...
Test = Other.Test;
...
return *this;
}
But this is not working since the move assignment of class A is not called.
Instead I was able to make the program work by using this method:
B& B::operator=(B&& Other)
{
...
Test = std::move(Other.Test);
...
return *this;
}
I do not understand why the first method is not working. I was thinking that since a constructor will call its members constructors the move assignment operator should do the same. Am I wrong or I made a mistake in my code? Can someone explain, thanks!
Other.Test is not an rvalue expression since it has a name. OTOH std::move(Other.Test) has the type A and the value category xvalue (i.e., an rvalue). Thus, it can bind to the move constructor.
(EDIT : Shamelessly copied #dyp's comment. Thanks, #dyp and #KerrekSB.)
#Pradhan is correct - you need to use std::move to move the members in the implementation of the move assignment operator. However, if that is all that is needed to implement your move constructor, then you can declare the operator to use the default implementation:
#include <memory>
class A {
public:
A() : p{} { }
~A() { }
A &operator=(A &&) = default;
// Instead of:
// A &operator=(A &&other) {
// p = std::move(other.p);
// return *this;
// }
private:
std::unique_ptr<int> p;
};
int main() {
A a;
A b;
b = std::move(a);
return 0;
}

Resources