I'm not sure how to use array variables with objects. How do you initialize an array when an object is created. An array that is a data member of an object.
I'm hoping to use an initialization list.
If your compiler supports it, you can do it like this:
struct Foo
{
int n[5];
Foo() :n{1,2,3,4,5} {}
};
Soon enough, that will be standard. GCC supports it now, I'm not sure what other compilers do.
An array member variable can only be default-initialized, you cannot provide explicit initialization values.
struct Foo {
Foo() : bar() {} // Default-initialize bar, for int this means initialize with 0
int bar[10];
};
If you want anything else, you'll have to assign in the constructor body.
struct Foo {
Foo() : bar() {
bar[3] = 1;
}
int bar[10];
};
Related
class MyClass {
};
struct myStruct {
MyClass instance;
};
struct myStructReference {
MyClass& instance;
};
struct myStructPointer {
MyClass* instance;
};
int main() {
// EDIT: works!
myStruct b;
// also doesn't work
// myStructReference c;
// works
myStructPointer d;
}
The error I get is: 'myStructReference::myStructReference()' is implicitly deleted because the default definition would be ill-formed:.
It appears as though C++ goes through the motions of creating a default constructor for a struct, but then fails. I suppose this makes sense, since a struct is nearly identical to a class under the hood, just struct has all default public members + inheritance.
Is it because we can automatically assign a pointer to initialize as NULL, whereas we can't with a reference?
Asking to learn!
myStructReference::instance is, well, a reference. References MUST always be initialized. In this case, you reference is not initialized, so it won't compile.
Suppose I have a class Foo, with a member variable that is a std::vector of floats, bar. I then create an instance of Foo, called foo. Let's say that I do not know the length of bar before the program runs, but at the point when foo's constructor is called, I know that it's length should be x.
There are three ways I can think of to initialize the length of bar, and I'm just wondering which of the three most people tend to use. I have ranked them in order of what I would consider to be "best practice", but I'm more curious about what method people "actually" use in practice. Sometimes I use methods which make the code clearer to follow, rather than necessarily following best practice...
bar is a private member, and I resize it during foo's constructor, e.g. Foo foo(x){bar.resize(x)};
bar is a private member, and I call foo.ResizeBar(x) which resizes bar internally, after creating foo.
bar is a public member, and I call foo.bar.resize(x), after creating foo.
Or, in code:
1.
class Foo
{
private:
std::vector<float> bar;
public:
Foo(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo(100);
return 0;
}
2.
class Foo
{
private:
std::vector<float> bar;
public:
Foo()
{
};
void ResizeBar(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo;
foo.ResizeBar(100);
return 0;
}
3.
class Foo
{
public:
std::vector<float> bar;
Foo()
{
};
};
int main()
{
Foo foo;
foo.bar.resize(100);
return 0;
}
The problem with all three of your methods is that you're needlessly invoking the default initializer for your vector, and then modifying the already initialized vector to suit your needs.
You should be invoking the correct initializer using the initializer list:
Foo::Foo(std::size_t x) : bar(x, 0) { }
The best method is not in the list of options you posted. The best method is to initialize bar using member initializer lists.
Foo::Foo(int x) : bar(x) {}
Suppose I have a class Baz that inherits from classes Foo and Bar, in that order. The constructor for class Bar takes a pointer to a Foo object. What I would like to do is to pass this as the Foo object to the Bar constructor:
Baz () : Foo(), Bar(this) {}
A working example:
#include <iostream>
class Bar;
class Foo {
public:
virtual ~Foo() {}
virtual void parse_bar (Bar&) const = 0;
};
class Bar {
private:
const Foo * parser;
public:
Bar (const Foo * parser_in) : parser(parser_in) {}
virtual ~Bar() {}
void parse_self () { parser->parse_bar (*this); }
};
class Baz : public Foo, public Bar {
public:
Baz () : Foo(), Bar(this) {}
virtual void parse_bar (Bar &) const { std::cout << "Hello World\n"; }
};
int main () {
Baz baz;
baz.parse_self();
}
This happens to work on my computer, with my compilers (tested with a couple of them). However section 9.3.2 of the 2003 standard makes me a bit uneasy that I might just be getting lucky, that using this this way is undefined behavior. Strictly speaking, the initializer list is outside the body of the constructor. Here's the relevant text, emphasis mine:
9.3.2 The this pointer
In the body of a nonstatic member function, the keyword this is a non-lvalue expression whose value is the address of the object for which the function is called.
So is my usage legal and well-defined, or is it undefined behavior?
There are two points that have to be noted in this case.
Firstly, in the constructor initializer list this pointer refers to a non-constructed (or not-fully-constructed) object. It is OK to access such pointer, but the object it refers to can only be used in limited ways. See 12.7 in the language specification.
Secondly, in your specific example what you are actually doing is converting this pointer to Foo * type before attempting any access. This is completely safe since by that moment the Foo subobject is fully constructed. (I assume that, whatever access will follow, if any, will be restricted only to the fully constructed Foo subobject).
The only concern is this case is whether it is legal to convert this to Foo * type, i.e. whether the conversion process itself should succeed. The answer is: yes, in case of ordinary (non-virtual) inheritance such conversion is perfectly legal and safe (again, explicitly allowed in 12.7)
It is fine. The C++ standard actually clarifies the use of this pointers in initializer lists:
12.6.2 Initializing bases and members [class.base.init]
Paragraph 7: Names in the expression-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) {}
};
initializes X::r to refer to X::a, initializes X::b with the
value of the constructor parameter i, initializes X::i with the
value of the constructor parameter i, and initializes X::j with
the value of X::i; this takes place each time an object of class X
is created. ] [Note: because the mem-initializer are evaluated in
the scope of the constructor, the this pointer can be used in the
expression-list of a mem-initializer to refer to the object being
initialized. ]
The type of the this pointer in the initializer of Baz is in fact of type Baz. Of course, you have to be mindful of the fact that not all of the members may have been initialized. Many, if not all, compilers set at their highest warning levels (which you really should be doing anyway) will warn about you passing a this pointer to the base class.
However, it looks like you're making it more complicated that it needs to be. Why not just put the virtual function parse_bar() in the Bar class, and forget about the Foo class?
#include <iostream>
class Bar
{
public:
Bar() {}
virtual ~Bar() {}
void parse_self () { parse_bar(); }
private: // Template method pattern
virtual void parse_bar() const = 0;
};
class Baz : public Bar
{
public:
Baz () {}
private: // Yes, this does override the private `parse_bar()` member!
virtual void parse_bar() const { std::cout << "Hello World\n"; }
};
int main ()
{
Baz baz;
baz.parse_self();
}
This does essentially the same function but with less code.
If I have a simple struct Foo, defined like this, it's a POD:
#include <iostream>
#include <type_traits>
struct Foo {
int a;
int b;
bool c;
};
int main() {
std::cout << (std::is_pod<Foo>::value ? "POD" : "NON POD") << '\n'; // Prints "POD"
}
Now imagine I want to default initalize the members and directly do:
struct Foo {
int a;
int b;
bool c = true;
};
The struct is no longer a POD! Even with a constructor like this:
struct Foo {
int a;
int b;
bool c;
Foo() : a(0), b(0), c(false) {}
};
Foo has lost its PODness...
Now the tricky part begins. Imagine I want to add a constructor taking an a:
struct Foo {
int a;
int b;
bool c;
Foo(int a) : a(a), b(0), c(false) {}
};
Now Foo is definitely not a POD. BUT if a add a default constructor:
struct Foo {
int a;
int b;
bool c;
Foo() = default;
Foo(int a) : a(a), b(0), c(false) {}
};
Foo is now a POD!
So as you can see, even if I simply want to use a default value like in the second example, I lose the PODness, but I can regain it as long as I define an explicit default constructor.
So the question is: should we always add a default constructor so we can benefit from the PODness of the class and improve performance? It's too bad to lose performance just because I wanted to default initialize some members...
In other words, defining default value like in the second example makes the struct non POD and non trivial, which is bad performance-wise, so how can I default initialize values and keep the struct trivial? A simple solution would be to define an initFoo function that returns a default initialized Foo, like for example:
Foo initFoo() {
Foo foo;
foo.a = 0;
foo.b = 1;
foo.c = true;
return foo;
}
But this is not very C++, but is it the right thing to do anyway?
should we always add a default constructor so we can benefit from the PODness of the class
If you want a class to be POD, then it must be trivially default constructible, among the other requirements.
One way to achieve that requirement is to not declare any constructors nor default member initialisers. Another way is to define the default constructor as default. Latter is the only way if you want the class to have any non-default constructors.
It doesn't matter which approach you pick as far as PODness is concerned.
but is it the right thing to do anyway?
Your initFoo is a right way to return a Foo with specific values. Personally, I don't see value in the local variable, and would do this instead:
return {
0,
1,
true,
};
Unfortunately, we lose member names from the initialisers, at least until C++20 where we can write:
return {
.a = 0,
.b = 1,
.c = true,
};
In C++, it's not possible to initialize array members in the initialization list, thus member objects should have default constructors and they should be properly initialized in the constructor. Is there any (reasonable) workaround for this apart from not using arrays?
[Anything that can be initialized using only the initialization list is in our application far preferable to using the constructor, as that data can be allocated and initialized by the compiler and linker, and every CPU clock cycle counts, even before main. However, it is not always possible to have a default constructor for every class, and besides, reinitializing the data again in the constructor rather defeats the purpose anyway.]
E.g. I'd like to have something like this (but this one doesn't work):
class OtherClass {
private:
int data;
public:
OtherClass(int i) : data(i) {}; // No default constructor!
};
class Foo {
private:
OtherClass inst[3]; // Array size fixed and known ahead of time.
public:
Foo(...)
: inst[0](0), inst[1](1), inst[2](2)
{};
};
The only workaround I'm aware of is the non-array one:
class Foo {
private:
OtherClass inst0;
OtherClass inst1;
OtherClass inst2;
OtherClass *inst[3];
public:
Foo(...)
: inst0(0), inst1(1), inst2(2) {
inst[0]=&inst0;
inst[1]=&inst1;
inst[2]=&inst2;
};
};
Edit: It should be stressed that OtherClass has no default constructor, and that it is very desirable to have the linker be able to allocate any memory needed (one or more static instances of Foo will be created), using the heap is essentially verboten. I've updated the examples above to highlight the first point.
One possible workaround is to avoid the compiler calling the OtherClass constructor at all, and to call it on your own using placement new to initialize it whichever way you need. Example:
class Foo
{
private:
char inst[3*sizeof(OtherClass)]; // Array size fixed. OtherClass has no default ctor.
// use Inst to access, not inst
OtherClass &Inst(int i) {return (OtherClass *)inst+i;}
const OtherClass &Inst(int i) const {return (const OtherClass *)inst+i;}
public:
Foo(...)
{
new (Inst(0)) OtherClass(...);
new (Inst(1)) OtherClass(...);
new (Inst(2)) OtherClass(...);
}
~Foo()
{
Inst(0)->~OtherClass();
Inst(1)->~OtherClass();
Inst(2)->~OtherClass();
}
};
To cater for possible alignment requirements of the OtherClass, you may need to use __declspec(align(x)) if working in VisualC++, or to use a type other than char like:
Type inst[3*(sizeof(OtherClass)+sizeof(Type)-1)/sizeof(Type)];
... where Type is int, double, long long, or whatever describes the alignment requirements.
What data members are in OtherClass? Will value-initialization be enough for that class?
If value-initialization is enough, then you can value-initialize an array in the member initialization list:
class A {
public:
A ()
: m_a() // All elements are value-initialized (which for int means zero'd)
{
}
private:
int m_a[3];
};
If your array element types are class types, then the default constructor will be called.
EDIT: Just to clarify the comment from Drealmer.
Where the element type is non-POD, then it should have an "accessible default constructor" (as was stated above). If the compiler cannot call the default constructor, then this solution will not work.
The following example, would not work with this approach:
class Elem {
public:
Elem (int); // User declared ctor stops generation of implicit default ctor
};
class A {
public:
A ()
: m_a () // Compile error: No default constructor
{}
private:
Elem m_a[10];
};
One method I typically use to make a class member "appear" to be on the stack (although actually stored on the heap):
class Foo {
private:
int const (&array)[3];
int const (&InitArray() const)[3] {
int (*const rval)[3] = new int[1][3];
(*rval)[0] = 2;
(*rval)[1] = 3;
(*rval)[2] = 5;
return *rval;
}
public:
explicit Foo() : array(InitArray()) { }
virtual ~Foo() { delete[] &array[0]; }
};To clients of your class, array appears to be of type "int const [3]". Combine this code with placement new and you can also truly initialize the values at your discretion using any constructor you desire. Hope this helps.
Array members are not initialized by default. So you could use a static helper function that does the initialization, and store the result of the helper function in a member.
#include "stdafx.h"
#include <algorithm>
#include <cassert>
class C {
public: // for the sake of demonstration...
typedef int t_is[4] ;
t_is is;
bool initialized;
C() : initialized( false )
{
}
C( int deflt )
: initialized( sf_bInit( is, deflt ) )
{}
static bool sf_bInit( t_is& av_is, const int i ){
std::fill( av_is, av_is + sizeof( av_is )/sizeof( av_is[0] ), i );
return true;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
C c(1), d;
assert( c.is[0] == 1 );
return 0;
}
Worth noting is that in the next standard, they're going to support array initializers.
Use inheritance for creating proxy object
class ProxyOtherClass : public OtherClass {
public:
ProxyOtherClass() : OtherClass(0) {}
};
class Foo {
private:
ProxyOtherClass inst[3]; // Array size fixed and known ahead of time.
public:
Foo(...) {}
};
And what about using array of pointers instead of array of objects?
For example:
class Foo {
private:
OtherClass *inst[3];
public:
Foo(...) {
inst[0]=new OtherClass(1);
inst[1]=new OtherClass(2);
inst[2]=new OtherClass(3);
};
~Foo() {
delete [] inst;
}
};
You say "Anything that can be initialized using only the initialization list is in our application far preferable to using the constructor, as that data can be allocated and initialized by the compiler and linker, and every CPU clock cycle counts".
So, don't use constructors. That is, don't use conventional "instances". Declare everything statically. When you need a new "instance", create a new static declaration, potentially outside of any classes. Use structs with public members if you have to. Use C if you have to.
You answered your own question. Constructors and destructors are only useful in environments with a lot of allocation and deallocation. What good is destruction if the goal is for as much data as possible to be allocated statically, and so what good is construction without destruction? To hell with both of them.