I have a class Printer with
class Printer{
struct foo{
int i;
};
foo & f;
};
and when I call the constructor of Printer, I need to initialize f since f is a reference, but what I want is first call the constructor of foo and create a instance of it then assign it to f. The problem I have is if I call
Printer::Printer():f(foo(0)){ }
There is an error saying I cannot use reference to a temporary instance of a structure. Any way around this problem?
Thanks
A reference doesn't make any sense in this situation. Try the following instead:
class Printer{
struct foo{
int i;
foo(int i_) : i(i_) {} // Define a constructor
};
foo f; // Not a reference anymore!
public:
Printer::Printer() : f(0) {} // Initialise f
};
I think you actually don't want a reference to foo but foo itself.
When you call foo(0), it creates a structure and returns it as a 'floating' object. You can't assign a reference to it, because no-one 'holds' it and it will be discarded as soon as the constructor exits.
So, if you would like to keep a reference to it, you would first have to store it in an actual object which would be persistent. In this case, you probably want to just keep the whole struct in the class.
You can make Oli's answer slightly shorter by declaring struct foo and defining f in one step:
class Printer{
struct foo{
int i;
foo(int i_) : i(i_) {}
} f;
public:
Printer() : f(0) {}
};
Related
I have a class MyClass in which I need to create a std::array of std::vector in the default constructor. However, this class has a data member which is a reference (of type Something) which also needs to be initialized in the constructor and I cannot do this in a default constructor.
How should I solve this?
class MyClass{
public:
MyClass(); //Cannot instantiate s??
MyClass(Something& s);
Something& s;
}
MyClass array[10]; // MyClass needs a default constructor but a default
// constructor won't be able to initialize s
A class with a reference member needs to set the reference in its constructors. In most cases this means, that the class cannot have a default constructor. The best way to solve the problem is use a pointer instead of a reference:
class MyClass{
public:
MyClass() : s_(0) {}
MyClass(Something* s) : s_(s) {}
Something* s_;
}
As I commented above, by the description alone, I would say that it's a classical case where s should be a Something* rather than a Something&...
OTOH, this work perfectly, so you don't need a default constructor if you just initialize each element of your array:
struct Something { };
struct MyClass {
MyClass(Something& ss) : s{ss} {}
Something& s;
};
int main() {
Something a, b, c, d;
Something v[10] = { a, b, c, d, a, b, c, d, a, b };
return 0;
}
Your can also do this:
class MyClass{
public:
MyClass() : s_(0) {}
MyClass(Something& s) : s_(&s) {}
Something* s_;
}
You can use std::optional<std::reference_wrapper<Something>> instead of Something&, this way you simulate Something* behavior but using modern C++ concepts.
note that you should check if member variable defined this way has value by calling has_value function and get the actual reference value by s_.value().get()
you also could use std::optional<std::reference_wrapper<const Something>> if you need a const reference to Something
Consider the following code:
class Foo {
Foo() {}
};
class Bar {
Foo &Foo_ref;
Bar() : Foo_ref() {}
};
Complied as is, I get the error:
tmp.cc: In constructor Bar::Bar():
tmp.cc:7: error: value-initialization of Foo& Bar::Foo_ref, which has reference type
I've tried every variation I can think of. What am I doing wrong? How do I initialize a reference member to a new instance?
I'm using a const pointer instead of a reference as a workaround for now, but I'd prefer to use a reference.
A reference must always be binded to an object. You have to pass an object you want to have reference to in your constructor
Bar(Foo &foo) : Foo_ref(foo)
{
}
If you don't want (or can't) pass Foo into Bar constructor - you have to use pointer:
class Bar {
Foo *Foo_ptr;
Bar() : Foo_ptr(nullptr) {}
};
You can think about the reference member variable as a pointer which must be binded in initializer list
What's wrong with
class Bar
{
Foo myFoo;
Bar() : myFoo() {}
};
if you want a brand-new Foo object?
Your constructor has to either take a parameter, set the reference to a member that is initialized before the reference or set the reference to a global Foo object. You can't bind the reference to a temporary (which, even if the reference is const, would only live until the constructor ends.
extern Foo gFoo;
class Bar {
Foo foo;
Foo &Foo_ref;
Bar() : Foo_ref(gFoo) {}
//or
//Bar() : Foo_ref(foo) {}
Bar(Foo& foo) : Foo_ref(foo) {}
};
I am wondering if I am using the good approach in the following :
I want to construct a parent class (class A), this class should own an instance of a given "Foo" class
I want the parent class to own a child class member (class B) and this member should have a reference to the foo member of the parent class.
The code below seems to works, however I am wondering whether I was just "lucky" that the compiler was sympathetic enough.
For clarity, I added comment and my question in the comments below.
Thanks !
struct Foo
{
std::string mValue;
};
class B
{
public:
B(const Foo & foo) : mFoo_External(foo) {}
private:
const Foo & mFoo_External; //this is an external reference to the member
//(coming from A)
};
class A
{
public:
//Here is the big question
//Shall I use :
// A(const Foo & foo) : mFoo(foo), mB(mFoo) {}
// or the declaration below
A(const Foo & foo) : mFoo(foo), mB(foo) {}
private:
//According to my understanding, the declaration
//order here *will* be important
//(and I feel this is ugly)
const Foo mFoo;
B mB;
};
void MyTest()
{
std::auto_ptr<Foo> foo(new Foo());
foo->mValue = "Hello";
A a( *foo);
foo.release();
//At this point (after foo.release()), "a" is still OK
//(i.e A.mB.mFooExternal is not broken, although foo is now invalid)
//
//This is under Visual Studio 2005 :
//was I lucky ? Or is it correct C++ ?
}
No, this is broken. Your mB will hold a reference to whatever you passed to the constructor of the A object, not to mFoo. Instead, you should say:
A(const Foo & foo) : mFoo(foo), mB(mFoo) { }
Note that mB is a copy of the constructor argument, and not a reference, so your MyTest function is fine.
Since you want your B object to hold a reference to the parent's member, you must initialize mB with mFoo not foo.
You are correct that the order of the member variables is important, since it determines the order of the initialization. It might come as a surprise that the order of the initializers in the constructor does not determine the order they are called! See Constructor initialization-list evaluation order.
class A;
class B {
public:
B(A& a) : a(a) {}
private:
A& a;
};
/* Method 1 */
/* warning C4355: 'this' : used in base member initializer list */
/*
class A {
public:
A() : b(*this) {}
private:
B b;
};
*/
/* Method 2 */
/* But I need to manually perform memory dellocation. */
class A {
public:
A() { b = new B(*this); }
~A() { delete b; }
private:
B* b;
};
int main() {
}
Currently, when I try to initialize the reference in B, I am using Method 1. However, Method 1 will flag me warning which is understandable.
Hence, I have to fall back using Method 2, by using dynamic memory allocation.
Is there any better way I can use, without the need of manual memory allocation/ dellocation (OK. I know smart pointer)?
I prefer Method 1, just that I am not comfortable with the warning.
Note this is a warning (so it is dangerous not illegal).
What the compiler is worried about is that you are passing a pointer for an object that has not been fully initialized. Thus if the pointer is used in the B class constructor you are in undefined behavior.
So if you do use this the only thing you can do is assign the pointer to a member variable (reference or pointer). But note be careful of the assignment to a variable as you may invoke an implicit cast (I am not sure if that is actually a problem but the RTTI is not available until the object is fully formed).
What are you trying to achieve by storing the reference?
Doing this is valid.
However, you must ensure (I mean by yourself, there's no way the compiler can do this) that the this is not used to call virtual functions until the object is fully constructed.
Depending on what you're doing, a method might be to factor out the parts of A that B needs, than have A inherit from the part.
struct bar_base; // interface foo wants
struct foo
{
foo(bar_base& pX) :
mX(pX)
{}
bar_base& mX;
};
struct bar_base
{
/* whatever else */
protected:
bar_base& get_base(void)
{
// getting `this` went here; safe because bar_base is initialized
return *this;
}
};
struct bar : bar_base
{
bar(void) :
// bar_base is already initialized, so:
mX(get_base())
{}
foo mX;
};
Obviously, this depends on what you're doing. This makes sure you never get undefined behavior.
But really, it's just warning. If you promise to never use this in B's constructor, you're fine, and can silence the warning this way:
struct bar;
struct foo
{
foo(bar& pX) :
mX(pX)
{}
bar& mX;
};
struct bar
{
bar(void) :
mX(self())
{}
foo mX;
private:
bar& self(void)
{
// fools the warning
return *this;
}
};
Make sure you know what you're doing, though. (Perhaps it could be re-designed?)
Well, one obvious way to avoid the warning is to make B store a pointer-to-A, then you don't have to initialise it in B's constructor/A's initialiser list, and can wait until the body of A's constructor is executing....
Take this warning seriously. Your this object is not yet fully constructed and passing around is not safe (if you ever accidentally call a function on this you invoke UB). Also, there are other techniques for memory management. Try looking up the STL design of allocators.
You could also use RAII/smart pointers to achieve the same effect.
Or, are you trying to write a garbage collector/memory profiler of sorts?
I've trying to achieve something like this:
class Base
{
public:
Base(string S)
{
...
};
}
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
Now, this doesn't work as I want, because bar() is called in the Derived constructor before foo is initialized.
I considered adding a static function similar to bar() which takes foo as a parameter - and using that in the initialization list, but thought I'd ask if there were any other techniques that could be used to dig myself out of this one...
Edit: Thanks for feedback - here's how I was going to handle the static function. Not sure if the overload between a static and non-static function is too clever, but...
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
}
string bar()
{
return bar(foo);
};
Derived(int f) : Base(bar(f)) , foo(f)
{
};
}
Yes, using a function (static class method or regular function) that takes foo as a parameter and returns a string is a good solution. You can call this same function from Derived::bar to prevent code duplication. So, your constructor would look like this:
Derived(int f) : Base(stringof(f)), foo(f) {}
I place the call to the Base constructor first in the list to emphasize the order in which the initializations occur. The ordering of the initializer list has no effect as all class members are initialized in the order that they are declared in the class body.
This is a very clean, functional approach to the problem. However, if you still would like to weigh alternatives then consider using composition instead of inheritance for the relationship between the Derived and Base classes:
class Base {
public:
Base(string S) { ... }
void bat() { ... }
};
class Derived {
Base *base;
int foo;
public:
Derived(int f) : base(NULL), foo(f) {
base = new Base(bar());
}
~Derived() {
delete base;
}
string bar() {
return stringof(foo); // actually, something more complex
}
void bat() {
base->bat();
}
};
You will need to consider the pros and cons for your specific situation. With Derived holding a reference to Base you gain greater control over the initialization order.
You can only call static functions in the initializer list. The way you have it in your code:
class Derived: Base
{
public:
int foo;
string bar()
{
return stringof(foo); // actually, something more complex
};
Derived(int f) : foo(f), Base(bar())
{
};
}
Will still initialize Base first, and then foo. The order of how you write things in an constructor initializer list does not matter in any way. It will always construct in this order:
First, all virtual base classes
Then the non-virtual base classes in the order they appear in the base-classes list
Then all member objects in the order they are defined in the class definition.
Thus, you end up calling stringof with an uninitialized value. This problem is solved in boost::base_from_member. Also note that calling any nonstatic member function before all the constructor initializers of all base-classes completed is undefined behavior.
Calling static functions, however, is totally fine:
class Derived: Base
{
public:
int foo;
static string bar(int f)
{
return stringof(f); // actually, something more complex
};
Derived(int f) : Base(bar(f)), foo(f)
{
};
}
The base class constructor always gets called before initializing the other members of the derived class; your compiler should be giving you a warning for having the initializers in the wrong order. The only correct solution is to make bar() a static method that takes f as a parameter.
The constructor is for, well, constructing the object. This means that, until it returns, there isn't an object there, and therefore that calling member functions just isn't going to work reliably. As everybody else says, use a static function or a non-member function.
I've been wanting to do this as well, but I gave up in the end.
Any suitable function call could be used as the parameter of Base().
Another option is to add and alternative constructor to Base that takes an int and does the conversion to 'string' itself.
Just move your constructor code to an Initialize() function and call it from the constructor. This is much simpler than static/nonstatic overriding or anything like that.