Initialization of a struct instance data member in constructor? - c++

I have a c++ class which as a private data member has a struct defined:
Class example {
...
private:
struct Impl;
Impl& structure_;
};
Assuming that the struct Impl is defined as follows:
struct example::Impl{
int m1;
int m2;
int m3;
};
how would I be able to initialize the struct instance ( structure_ ) in the class's constructor?
Right now I have:
example::example() :
structure_ .m1(00),
structure_ .m2(00),
structure_ .m3(00) {
...
}
.. for the initialization list, but I'm getting this error:
'example::structure_' : must be initialized in constructor base/member initializer list
how would I fix this?
Thanks

Impl is a reference, so you need to initialize it with an actual Impl object before it can be used.

If you're going for the pImpl idiom, use a pointer, and allocate + deallocate it in the class, then assign to it inside the ctor.
Class example {
...
private:
struct Impl;
Impl* pimpl_
};
example::example() :
pimpl_(new Impl())
{
pimpl_->m1 = 00;
pimpl_->m2 = 00;
pimpl_->m3 = 00;
...
}
example::~example(){
delete pimpl_;
}
If you really want a reference, dereference the returned pointer from new and take its address again when deleting it:
example::example() : impl_(*new Impl(), ...
example::~example(){ delete &impl_; }

Since your structure_ is a reference, it needs to be referenced by something that is created outside of your "example" class. You could either change the reference into a pointer and allocate the structure somehow, or define the structure in the class-definition, allowing you to instance it directly instead of using a reference.

You store your struct by reference in your class. A reference must point to a physical object, you can do two things. Store the object by value or by pointer.

Related

Pass Interface object to constructor c++?

Say i have an interace like
#include<iostream>
struct Interface
{
virtual void fun() = 0;
};
struct IType : Interface
{
void fun() override
{
std::cout<<"non const fun()";
}
};
class Type
{
private:
Interface &intr; // I can't declare intr as const i need to ascess non const fun()
public:
// I put it as a const for default value
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)} // Is const_cast is safe or how to do it ?
// What is god idea to do it should i need to remove const and default value but i need a default constructor
{
intr.fun();
}
};
int main()
{
Type obj;
return 0;
}
Thanks.
Reference as class member is rarely a good idea. You need an object, passed from the outside, that will outlive your class object. You cannot use default argument and you cannot use a temporary for initialization. Typically, if you need to pass different types that inherit from an interface, this is solved with (smart) pointers.
Type(const Interface& obj = IType()) : intr{const_cast<Interface&>(obj)}
//Is const_cast is safe or how to do it ?
It depends. You can cast away constness only if the real object is not const. So this:
IType itype{};
Type {itype};
would be valid, but this:
const IType itype{};
Type {itype};
would be invalid.
Your default argument is invalid anyway, because that default is a temporary object that dies immediately once constructor finishes, which means you cannot use intr member outside of this constructor.
I'm not 100% sure if const_cast is valid on temporary or not, but that doesn't matter in this case.
The solution is to use (smart) pointers:
class Type
{
private:
std::shared_ptr<Interface> intr;
public:
Type(std::shared_ptr<Interface> obj = std::make_shared<IType>()) : intr{std::move(obj)}
{
intr.fun();
}
};
The default choice for smart pointer is std::unique_ptr, but use of reference suggests that you wanted access to object from the outside of the class as well, and std::shared_ptr will allow that.

Why can we only initialize structs with primitive types or pointers?

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.

Accessing Class Data from Declared Struct

Alright, so I've tried a few ways to deal with this issue, but I can't seem to fix it.
In my header file I have:
class MyClass {
public:
bool test;
struct MyStruct;
};
I also have a constructor and all that, but that's not the important/not causing errors
In the cpp what I want to do is this:
MyClass::MyStruct {
test=true;
};
The problem with this, is that the struct is unable to access the test variable. How can I pass the current instance's variable to the struct or some other way to allow the struct to access the variable.
This:
MyClass::MyStruct {
test=true;
};
Is not at all valid C++ code. Perhaps you meant this:
MyClass::Class() {
test=true;
}
Which would make a default constructor of MyClass which sets test to true. But your question makes it seem like you want to set the value of MyClass::test from MyClass::MyStruct. This is not really possible, because a nested class (or struct, in your case) does not "inherit" or "contain" or really have almost any special relationship with its enclosing class (or struct).
Another possibility is this:
class MyClass {
public:
static bool test;
struct MyStruct;
};
MyClass::MyStruct::MyStruct() {
test=true;
}
Which would make a default constructor of the nested struct which sets a variable in the enclosing class, but the variable then needs to be static, meaning there's only one in the whole program, not a separate value per instance of either class or struct.
Seems to me if MyStruct is executing code it should be a class. And if so, you either pass it an instance of the MyClass (e.g. this if calling from MyClass), or pass it a reference to the member it needs (e.g. this->test)...
You can declare the structure as a friend in the class definition.
class MyClass {
public:
bool test;
friend struct MyStruct;
};
Edit:
class MyClass {
friend class MyStruct(MyClass *myClass) : myClass(myClass) {
private:
MyClass *myClass;
}
MyStruct *myStruct;
bool test;
public:
MyClass() {
myStruct = new MyStruct(this);
}
}
Note: This is untested and just written in my browser. I know it's missing destructors and stuff.
Since you're passing the parent pointer to the member class, the member class can then access the parent class's private members because it was declared a friend.

C++: Passing reference of constructing object to constructed member objects?

Okay, consider the following classes:
class Object
{
public:
// Constructor
Object() :
[Initialization List]
{
...
}
...
};
class Container
{
public:
Object A;
Object B;
....
Container() :
[Initialization List]
{
}
};
I'd like to provide [access to Container and it's members] to the Objects.
My first thought was to somehow pass a reference to the current Container object to the constructors of the Objects. But I can't figure out how to do this.
I've messed around with "this", but I'm not getting anything that works. I tried something like this:
class Object
{
public:
Container& c
// Constructor
Object(Container& c_) :
c(c_)
{
...
}
...
};
class Container
{
public:
Object A;
Object B;
....
Container() :
A(Object(this))
B(Object(this))
{
}
};
My eventual goal is to be able to access Object B from inside a member method of Object A.
Does anyone have any insight on how to get closer to what I'm looking for?
Thanks!
It is not UB or bad, necessarily, to use this in an initializer list, although care is needed, and your code is perfectly valid with minor modification.
class Container;
class Object
{
public:
Container& c
// Constructor
Object(Container& c_) :
c(c_)
{
}
};
class Container
{
public:
Object A;
Object B;
Container() :
A(Object(*this))
B(Object(*this))
{
}
};
this is a pointer, you wanted a reference, and a simple de-reference will do the trick. This is perfectly legal and defined code. What's not allowed is to access any member data or functions through the pointer, because those member data or functions simply may not exist yet until the init list is finished. But it definitely is allowed to take a pointer or reference to an object during it's initializer list and pass it around.
How about just using pointers? Edit: fixed code to avoid this in initializer list.
class Container;
class Object
{
public:
Container *c;
// Constructor
Object(Container *c_) :
c(c_)
{
}
};
class Container
{
public:
Object *A, *B;
Container()
{
A = new Object(this);
B = new Object(this);
}
};
You shouldn't pass this in initializers for members of the class whose instance you're constructing, but you can pass it later, so there's two easy ways around your problem
use a setter on the object (A.setContainer(*this)) in the constructor's body
make A and B pointers, initialize them to NULL and do a A = new Object(this) in the constructor's body

Any workarounds for non-static member array initialization?

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.