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;
};
Related
I'm trying to write a layer for making some components of a project more modular. How can I make a class Foo exactly equal to a class Bar, where Foo would be able to be used as the variable 'a' in a function int testFunc(Bar a)?
Would the only solution be to have Foo have a definition like this?
class Foo {
public:
Foo(int a) : barReturn(a) {};
operator Bar() const { return barReturn; }
private:
Bar barReturn;
};
If you want a true alias, you might do an alias:
since C++11:
using Foo = Bar;
or the old way (still valid):
typedef Bar Foo;
May be you can use the polymorphism of c++.There are some diffrent components derived an interface Foo.
class Foo {
public:
virtual Foo(int a);
virtual Update(int a);
};
class Bar1 : public Foo{
public:
virtual Bar1(int a): m_a(a);
virtual Update(){
// TODO:
}
private:
int m_a;
};
class Bar2 : public Foo{
public:
virtual Bar1(int a): m_b(a);
virtual Update(){
// TODO:
}
private:
int m_b;
};
// There a module to do Foo
void ProcessModule(){
std::vector<Foo*> v;
v.push_back(new Bar1(1));
v.push_back(new Bar2(2));
for (std::vector<Foo*>::itreator it = v.begin(); v != v.end(); ++v){
it->UPdate()
}
}
Defining the classes A with private constructor and destructor (it should be so!) and B as a friend class, how can I creat a vector of A objects in B and fill it with the function addA(). I got the error "error C2248: "A::~A": No access to private members whose declaration was made in the A class".
class A
{
private:
A();
A(const std::string& name, const float& num);
~A();
public:
friend class B;
private:
std::string name_;
float num_;
};
A::A()
{
name_ = "NoName";
num_ = 0.0;
}
A::A(const std::string& name, const float& num)
{
name_ = name;
num_ = num;
}
A::~A()
{
}
class B
{
public:
B();
~B();
void addA(const std::string name, const float num);
private:
vector<A> vecA;
};
B::B()
{
}
B::~B()
{
}
void B::addA(const std::string name, const float num)
{
A a(name, num);
vecA.push_back(a);
}
int main()
{
B b;
b.addA("Name", 1.0);
return 0;
}
While #Fureeish has a neat solution, here's a slightly simpler alternative: just wrap it.
class AccessPrivate;
class PrivStuff
{
private:
PrivStuff() {}
~PrivStuff() {}
public:
friend class AccessPrivate;
std::string m_data{};
};
class AccessPrivate
{
public:
AccessPrivate() = default;
~AccessPrivate() = default;
PrivStuff m_priv;
};
int main(int argc, char* argv[])
{
std::vector<AccessPrivate> myvec;
myvec.resize(4);
for (auto& stuff : myvec)
{
stuff.m_priv.m_data = "heya";
}
}
If you need something more complicated, like passing in arguments, just add an equivalent constructor to AccessPrivate and there you go. You can essentially treat AccessPrivate almost like the actual private class, just one level of indirection.
how can I create a vector of A objects in B [...] ?
You can't do that. While B is a friend of A, std::vector is not a friend of A, which means that it cannot access private members of A, e.g., constructor, which is required for a vector to work.
However, if you are okay with a little indirection, little potential performance hit and a change in your signature, you can replace the not-working std::vector<A> with a workig std::vector<std::unique_ptr<A, deleter>>.
It's important to note that plain std::unique_ptr will not work here. It has a similar problem to std::vector - it cannot access private destructor of A. One way to work around it is to outsource the job of constructing and destructing of As entirely to B - via explicit construction and destruction, that is:
new A(name, num)
static void deleter_a(A* a) { delete a; }
in B's scope.
Now we can do:
std::vector<std::unique_ptr<A, std::function<void(A*)>>> vecA;
instead of: std::vector<A> or std::vector<std::unique_ptr<A>>. This is important - neither std::unique_ptr nor std::vector construct or destruct your As. B is entirely responsible for constructing (new A(name, num)) and destructing (static void deleter_a(A* a) { delete a; }) As.
Full B class:
class B {
public:
B() {}; // or = default
~B() {}; // or = default
void addA(const std::string name, const float num);
private:
static void deleter_a(A* a) { delete a; }
using deleter_a_t = void(A*);
std::vector<std::unique_ptr<A, std::function<deleter_a_t>>> vecA;
};
void B::addA(const std::string name, const float num) {
vecA.push_back(std::unique_ptr<A, std::function<deleter_a_t>>{
new A(name, num), std::function<deleter_a_t>{deleter_a}
});
}
Contrary to what the other answers say, it is possible to do this without any extra indirection.
std::vector doesn't directly call the constructor and the destructor, but uses an allocator. If you want an std::vector to manage A objects, you just need to provide it an allocator that implements the construct and destroy functions, and that is either a friend of A or a nested class of B (since B is already a friend of A).
Example:
#include <memory>
#include <utility>
#include <vector>
class A {
A() = default;
~A() = default;
friend class B;
};
class B {
template<typename T>
struct custom_alloc : std::allocator<T> {
template<typename U, typename... Args>
void construct(U* p, Args&&... args){
::new(const_cast<void*>(static_cast<const volatile void*>(p))) U(std::forward<Args>(args)...);
}
template<typename U>
void destroy(U* p){
if constexpr (std::is_array_v<U>){
for(auto& elem : *p){
(destroy)(std::addressof(elem));
}
} else {
p->~U();
}
}
};
public:
std::vector<A,custom_alloc<A>> vec;
void new_A(){
vec.push_back(A());
}
};
For the implementation of construct and destroy, I used an equivalent implementation of the c++20 versions of std::destroy_at and std::construct_at. I suspect that destroy is overkill and just a call to the destructor would be sufficient, but I'm not sure.
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.
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;
}
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.