struct foo
{
foo(int something) : m_something{ something } {}
foo() { }
private:
int m_something{};
};
struct bar
{
bar(foo& f)
:
m_foo{ f }
{ }
bar(int something)
:
m_default{ something } ,
m_foo{ m_default }
{
}
private:
foo m_default;
foo& m_foo;
};
bar class can be constructed by reference of foo or it can initialize the foo itself. I want to get rid of unnecessary initialization cost of m_default in case which bar is constructed by reference of foo. I know it can be solved by using pointers but I want to stay within stack.
Is it possible ?
Ted Lyngmo's answer just worked flawlessly. I am sharing full code :
#include <iostream>
struct foo;
struct foo_own;
// only holds a reference
struct foo_ref {
foo_ref(foo& fr) : m_foo(fr) {
std::cout << "foo_ref constructor is called\n";
}
virtual ~foo_ref() = default;
operator bool() { return false; }
operator foo&() { return m_foo; }
foo& operator*() { return m_foo; }
private:
foo& m_foo;
};
struct foo
{
foo(int something) : m_something{ something } {}
foo() { }
private:
int m_something{};
};
// owning a foo
struct foo_own : public foo_ref {
foo_own(int something) : foo_ref(m_default), m_default(something) {
std::cout << "foo_own constructor is called\n";
}
private:
foo m_default;
};
struct bar
{
bar(const foo_ref& f)
:
m_foo{ f }
{ }
bar(const foo_own& f)
:
m_foo{ f }
{ }
private:
const foo_ref& m_foo;
};
int main(int, char**) {
foo foo_l;
bar b{foo_l};
bar b2{15};
return 0;
}
and the output is
foo_ref constructor is called foo_ref constructor is called foo_own
constructor is called
You could divide it into two types of foo wrappers:
// only holds a reference
struct foo_ref {
foo_ref(foo& fr) : m_foo(fr) {}
virtual ~foo_ref() = default;
operator foo&() { return m_foo; }
foo& operator*() { return m_foo; }
private:
foo& m_foo;
};
// owning a foo
struct foo_own : public foo_ref {
foo_own(int something) : foo_ref(m_default), m_default(something) {}
private:
foo m_default;
};
To avoid future slicing and have a way of creating your foo_refs and foo_owns that looks very similar, you could add a couple of helper functions:
auto make_foo_wrapper_ptr(foo& f) {
return std::make_unique<foo_ref>(f);
}
auto make_foo_wrapper_ptr(int v) {
return std::make_unique<foo_own>(v);
}
You can use an std::variant that can either be empty (meaning hold an std::monostate) or hold a foo. m_foo should then be made to refer to the passed foo& in the first constructor, or the foo held by the variant in the second constructor.
In both cases, the rest of bar's code should just use m_foo regardless of how the instance was constructed, since either way it refers to a valid foo object.
This requires C++17 support.
#include <variant>
struct bar
{
// We do not initialize m_foo_var here so that it's going to be
// default constructed as empty.
bar(foo& f)
: m_foo(f)
{}
bar(int something)
: m_foo_var(something)
, m_foo(std::get<foo>(m_foo_var))
{}
private:
std::variant<std::monostate, foo> m_foo_var;
foo& m_foo;
};
Note that this gets rid of the initialization overhead, but not of the memory overhead. m_foo_var will still occupy sizeof(foo) bytes.
Related
Trying to allow make_unique on a class with private ctor I came into the following strange difference between two cases:
Case 1 - empty ctor - compiles
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create();
a->doIt();
}
Output:
7
Case 2 - non-empty ctor - doesn't compile
class A {
int _i;
A(int i): _i(i) {} // <- change 1, ctor getting int
public:
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create(7); // <- change 2, sending 7
a->doIt();
}
Compilation Error:
unique_ptr.h: error: calling a private constructor of class 'enablePrivateCtor'
Why the 1st one - with the empty ctor - is OK, while the 2nd - the non-empty ctor - is not?
The default constructor is never inherited. Therefore, the first enablePrivateCtor generates a default constructor, which calls the base class default constructor.
When you inherit a constructor (as in the second case), the new constructor has the same access level as the inherited one. So since A::A(int) is private, so too will be enablePrivateCtor::enablePrivateCtor(int). So you won't be able to construct with it.
If you need to have a private constructor be able to be called indirectly (through make_unique/emplace/etc), then you need to use a private key type. Like this:
class A;
class A_key
{
A_key() = default;
A_key(int) {} //Prevent `A_key` from being an aggregate.
friend class A;
};
class A {
int _i;
public:
A(int i, A_key): _i(i) {}
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t)
{
return std::make_unique<A>(std::forward<T>(t)..., A_key{});
}
void doIt() const {
std::cout << _i << std::endl;
}
};
...
auto ptr = A::create(7);
A a(7, A_key{}); //Does not compile, since you're not a friend.
A_key is publicly copyable, but it is not publicly default constructible. So non-private code can pass them around, but non-private code cannot create them.
The difference is that enablePrivateCtor automatically gets a default constructor (which is allowed to call A::A).
It doesn't automatically get an integer conversion constructor: add
enablePrivateCtor(int i) : A(i) {}
and see it work.
The code you posted has undefined behavior.
In particular, you allocate an enablePrivateCtor then delete an A.
A better way than this is to use a key type.
class A {
int _i;
A(): _i(7) {}
class construction_token_t {
explicit construction_token_t(int) {}
friend class A;
};
static auto ctor_token() {
return construction_token_t(0);
}
public:
template<class...Args>
A( construction_token_t, Args&&...args ):A(std::forward<Args>(args)...){}
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(ctor_token(), std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
We create a token which can grant another class the right to access our private ctor. The only one who can create this token is our class.
We then pass it to make_unique.
An alternative is to use the factory lambda pattern.
template<class F>
struct factory_lambda_t {
F f;
template<class T>
operator T() const { return f(); }
};
template<class F>
factory_lambda_t<std::decay_t<F>>
factory( F&& f ) { return {std::forward<F>(f)}; }
In C++14 this requires move/copy ctors to be public, but in C++17 it doesn't.
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(factory([&]{
return A(std::forward<T>(t)...);
}));
}
void doIt() const {
std::cout << _i << std::endl;
}
};
which I think is pretty slick.
This may result in eliding constructors completely in some cases. In others, a single move occurs.
class foo{
public:
bar steal_the_moveable_object();
private:
bar moveable_object;
};
main(){
foo f;
auto moved_object= f.steal_the_moveable_object();
}
How can implement steal_the_movebale_object to move the moveable_object into the moved_object ?
You can simply move the member directly in the return statement :
class foo
{
public:
bar steal_the_moveable_object()
{
return std::move(moveable_object);
}
private:
bar moveable_object;
};
Beware that this may not be a good idea though. Consider using the following instead so that the method can only called on R-Values :
class foo
{
public:
bar steal_the_moveable_object() && // add '&&' here
{
return std::move(moveable_object);
}
private:
bar moveable_object;
};
int main()
{
foo f;
//auto x = f.steal_the_moveable_object(); // Compiler error
auto y = std::move(f).steal_the_moveable_object();
return 0;
}
In C++, is there any way to have something like a temporary variable in an initialization list. I want to initialize two constant members with the same instance of something without having to pass that something in, remove the const requirement, use a Factory (i.e. pass it in but have the factory generate it to hide it from the API user), or have temp actually be a member variable.
I.e. something like
Class Baz{
const Foo f;
const Bar b;
Baz(Paramaters p):temp(p),f(p,temp),b(p,temp){ //temp is an instance of Something
// But NOT A member of Baz
// Whatever
}
}
instead of
Class Baz{
Foo f;
Bar b;
Baz(Paramaters p){
Something temp(p);
f = Foo(p,temp)
b = Bar(p,temp)
}
}
or
Class Baz{
Foo f;
Bar b;
Baz(Paramaters p,Something s):f(p,s),b(p,s){
}
}
In C++11 you could use delegating constructors:
class Baz{
const Foo f;
const Bar b;
Baz(Paramaters p) : Baz(p, temp(p)) { } // Delegates to a private constructor
// that also accepts a Something
private:
Baz(Paramaters p, Something const& temp): f(p,temp), b(p,temp) {
// Whatever
}
};
There's a couple of patterns to achieve this.
In C++11 use delegating constructors:
class Baz {
public:
Baz(Paramaters p) :
Baz{p, Something{p}}
{}
private:
Baz(Paramaters p, Something temp) :
f{p, temp},
b{p,temp}
{}
const Foo f;
const Bar b;
};
Use a base class:
class BazBase {
public:
BazBase(Paramaters p, Something temp) :
f{p, temp},
b{p,temp}
{}
protected:
const Foo f;
const Bar b;
};
class Baz : private BazBase {
public:
Baz(Paramaters p) :
BazBase{p, Something{p}}
{}
};
Use a factory method:
class Baz {
public:
static Baz make(Parameters p)
{
return {p, Something{p}};
}
private:
Baz(Paramaters p, Something temp) :
f{p, temp},
b{p,temp}
{}
const Foo f;
const Bar b;
};
For example, say I have the following code;
class Foo
{
public:
Foo(int x) : _foo(x)
{
}
private:
int _foo;
protected:
std::string _bar;
};
class Bar : public Foo
{
public:
Bar() : Foo(10), _temp("something"), _bar("something_else")
{
}
private:
std::string _temp;
};
int main()
{
Bar stool;
}
The code doesn't run because _bar is of the class Foo and it doesn't appear to know it exists, so is this not how you would go about doing it? Or would you just have _bar in Foo's constructor? This would work but what if _bar doesn't always have to be assigned something?
Edit: Below is the real code I was using;
Entity::Entity(GameState *state, bool collidable)
:_isLoaded(false), _state(state), alive(true), collidable(collidable), name(entityDetault)
{
}
Entity::Entity(GameState *state, bool collidable, entityName _name)
:_isLoaded(false), _state(state), alive(true), collidable(collidable), name(_name)
{
}
and then the child class would use this constructor;
Player::Player(GameState *state)
: Entity(state,true,entityName::entityPlayer), health(100),bulletSpeed(600),_colour(sf::Color(128,255,86,255))
Does this all look correct now? Slightly better than doing it all in the constructor body.
The member initialiser list in a constructor of class C can only initialise:
direct base classes of C
direct members of C
virtual base classes of C (doesn't come up too often)
The only way to initalise a member of a base class is through a constructor of the base class. Or just forego initialisation and then do an assignment in the body of C's constructor. The latter cannot be used for const members or references, though, and in general does not do the same thing as just initialisation.
You could either move it from the initializer list to the body (if it is not const):
Bar() : Foo(10), _temp("something")
{
_bar = "something_else";
}
or provide a second (maybe protected) contructor for Foo:
class Foo
{
public:
Foo(int x) : _foo(x)
{
}
protected:
Foo(int x,std::string s) : _foo(x), _bar(s)
{
}
private:
int _foo;
protected:
std::string _bar;
};
class Bar : public Foo
{
public:
Bar() : Foo(10,"something_else"), _temp("something")
{
}
private:
std::string _temp;
};
You need to initialize the base class before you can access it. If you want to initialize member variable in the base class, you have to do it via call to base class constructor in which will initialize it's members.
You may put _bar in Foo's constructor's initialization list. If _bar does not always need be to assigned something, you can use default value.
class Foo
{
public:
Foo(int x):_foo(x)
{
}
protected:
Foo(int x, string s) : _foo(x),_bar(s)
{
}
private:
int _foo;
protected:
std::string _bar;
};
class Bar : public Foo
{
public:
Bar() : Foo(10,"something else"), _temp("something")
{
}
private:
std::string _temp;
};
my question is as follows: Suppose I have:
class Foo
{
public:
Foo() {}
void setInt(int i) { myInt = i; }
int getInt() { return myInt; }
private:
int myInt;
};
class Bar
{
public:
Bar(Foo f) { /* do something with f.getInt() */ }
};
Now I have another class that has Bar as a member vairable:
class BarUser
{
public:
BarUser();
private:
Bar bar;
};
I want to write BarUser's constructor, however I want to initialize Bar with a Foo member that has 3 as its integer. I.e.:
Foo f;
f.setInt(3);
Bar b(f);
However since I have Bar as a class member, I cannot write all this code in the initialization list... What I mean is:
BarUser::BarUser() : bar(/* Foo after executing f.setInt(3) */)
{ ... }
Suppose assignment operator is not allowed for Bar - how can I initialize it as intended?
Thanks!
If you can't change Foo, write a function:
Foo make_foo(int i) {
Foo f;
f.setInt(i);
return f;
}
then initialize with bar(make_foo(3)).
You've sort of shot yourself in the foot by giving Foo a constructor but no int constructor. You might be better off adding an explicit constructor to Foo that takes an int.