C++ create static object without constructing it (without allocation) - c++

Im writing embedded code that cannot use memory allocation!
Also, static objects (therefore constructed before the microcontroller has executed the main funtion with all its initialization) shall be constructed within the main after the initialization, not before.
The only solution people suggest is to use static object pointers and allocate (construct them with new) during initialization. since this is no option for me, is there no other solution?
what i wanna do is as follows:
class A
{
public:
A(int a, bool b)
: myVal1(a), myVal2(b)
{
}
private:
int myVal1;
bool myVal2;
}
class B
{
public:
B(char x)
: myChar1(x) // <-- NO CONSTRUCTION, NO PARAMETER OF MYOBJECTA
{
}
void init()
{
// now i wanna construct myObjectA
myObjectA(123, false);
}
private:
char myChar1;
A myObjectA; // <-- NO CONSTRUCTION, NO PARAMETER
}
static B myObjectB('F'); // <-- NO CONSTRUCTION, NO PARAMETER OF MYOBJECTA
void global_init()
{
// ... do before construction
// now i wanna construct myObjectA
myObjectB.init();
//... do after construction
}

You can use a storage area large enough to create there an instance of A and placement new to control the time you create it.
As an example:
#include
#include
struct A {
A(int a, bool b): myVal1(a), myVal2(b) {}
void foo() {}
private:
int myVal1;
bool myVal2;
};
struct B {
B(char x): myChar1(x) {}
~B() { if(ptr) { ptr->~A(); } }
void init() {
ptr = new (&storage) A{123, false};
}
A * myObjectA() {
return ptr;
}
private:
char myChar1;
std::aligned_storage_t<sizeof(A), alignof(A)> storage;
A *ptr{nullptr};
};
static B myObjectB('F');
void global_init() {
// ... do before construction
// now i wanna construct myObjectA
myObjectB.init();
//... do after construction
}
int main() {
global_init();
myObjectB.myObjectA()->foo();
}
This won't allocate memory (if I got right what you mean for that) and the instance of A is actually created within B::init (that seems to be a requirement from what you wrote in your question).
If you have access to a compiler that supports C++17 or you can use the C++ Boost Libraries, std::optional is a valid alternative as suggested in another answer. Anyway you didn't specify the revision of the standard to which to adhere, so... Here is a way to go in any case.

Do you have boost available?
#include <boost/optional.hpp>
class A
{
public:
A(int a, bool b)
: myVal1(a), myVal2(b)
{
}
private:
int myVal1;
bool myVal2;
};
class B
{
public:
B(char x)
: myChar1(x) // <-- NO CONSTRUCTION, NO PARAMETER OF MYOBJECTA
{
}
A& getA() {
assert(myObjectA);
return myObjectA.get();
}
void init()
{
// now i wanna construct myObjectA
myObjectA.emplace(123, false);
}
private:
char myChar1;
boost::optional<A> myObjectA; // <-- NO CONSTRUCTION, NO PARAMETER
};
static B myObjectB('F'); // <-- NO CONSTRUCTION, NO PARAMETER OF MYOBJECTA
void global_init()
{
// ... do before construction
// now i wanna construct myObjectA
myObjectB.init();
//... do after construction
}
int main()
{
global_init();
}

Related

Call a member function automatically in the end of a scope

Is there a way to call a class member function automatically in the end of a scope?
Apparently if the class is instantiated within the same scope, clean() can be used in the destructor of it. The question is, can we achieve that if it is instantiated before the scope? In detail:
class foo
{
public:
void do_something() {}
void clean() {}
};
int main()
{
foo c;
{
c.do_something();
// do something
// call c.clean() automatically
}
}
Something like this. May not be exactly what you are looking for as it requires you do declare another variable at the start of the scope where you want the clean function to be called.
class CleanFoo
{
public:
CleanFoo(Foo& r) : ref(r) {}
~CleanFoo() { ref.clean(); }
CleanFoo(const CleanFoo&) = delete;
CleanFoo& operator=(const CleanFoo&) = delete;
private:
Foo& ref;
};
int main()
{
foo c;
{
CleanFoo cc(c);
...
} // c.clean() will be called here
...
}
std::unique_ptr actually has something like that, in the form of a second parameter you can pass to the constructor, a deleter. The deleter cleans up when the std::unique_ptr object goes out of scope. Normally (i.e. if you don't specify it) it would be std::default_delete that calls delete on the dynamically allocated memory it owns. But you can make it do other things, like this:
#include <cstdio>
#include <memory>
class foo
{
public:
void do_something() { printf("do_something\n"); }
void clean() { printf( "clean\n"); }
};
int main()
{
foo c;
{
std::unique_ptr<foo, void(*)(foo*)> scoped_cleaner(&c, [](foo* c) { c->clean(); });
c.do_something();
}
}
godbolt
Only thing that is called automatically at the end of the scope is the destructors of the objects whose lifetime end in that scope. As such, you could have another object local to the inner scope whose destructor calls the function.
A generic solution exists in Boost already:
foo c;
{
BOOST_SCOPE_EXIT(&c) {
c.clean();
};
c.do_something();
// do something
}
One caveat with all these answers including mine is that foo::clean() must not throw.
Write a do_guard. You can leverage RAII to create a wrapper that will call do on the object you give the wrapper in it's constructor, and then the destructor will call clear. That would look like
struct do_guard
{
foo& ref;
do_guard(foo& ref) : ref(ref) { ref.do_something(); }
~do_guard() { ref.clean(); }
};
int main()
{
foo c;
{
do_guard guard(c);
// do something
} // guard.~do_guard() will call c.clean() automatically
}
You can make do_something return something that gets its destructor called at the end of the scope:
class foo;
struct cleaner {
foo& f;
cleaner(foo& f) : f{f} {}
~cleaner();
};
class foo
{
public:
cleaner do_something() { return *this; }
void clean() {}
};
cleaner::~cleaner() { f.clean(); }
int main()
{
foo c;
{
auto x = c.do_something();
// do something
} // x calls c.clean() automatically
}

Vector of class object with private constructor and destructor?

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.

How I set a reference after constructor?

I want to set a reference after constructor
Example:
class OtherClass
{
public:
OtherClass() : m_class(Class()){}
inline void SetData(int data1, int data2)
{
//calculate data3
// I tried:
m_class = Class(data3);
//but it doesn't worked
}
protected:
private:
Class& m_class;
};
Edit:
The Exception is: vector subscript out of range
because I have glm vectors in the Class.
I need also call functions in my Class.
Edit 2:
Why I need this?
Because I have an other class [ExClass] which extends and which have to calulate in constructor:
ExClass::ExClass(float d1, float d2, ...) {
//calculate data from given values
SetData(data);
}
The proper way to do that is to use a pointer and not a reference, as opposed to references - pointers can be set after object creation. Note also that referring (or pointing) to a local variable whose lifetime will end, while still in use, is a bad idea.
Your code may be changed to use a pointer and dynamic allocation or alternatively, std::unique_ptr. There are of course other options, these are just examples.
Option 1 - a pointer and dynamic allocation
class OtherClass
{
public:
OtherClass() : m_class(nullptr){}
~OtherClass() {
delete m_class;
}
// block copy and assignment (or implement them)
OtherClass(const OtherClass&) = delete;
OtherClass& operator=(const OtherClass&) = delete;
void setData(int data1, int data2)
{
// ... calculate data3 ...
m_class = new Class(data3);
}
bool hasInnerObj() const {
return m_class; // or: return m_class != nullptr;
}
/** call this function only if hasInnerObj() returned true */
Class& getInnerObj() {
return *m_class;
}
private:
Class* m_class;
};
Option 2 - std::unique_ptr
class OtherClass
{
public:
void setData(int data1, int data2)
{
// ... calculate data3 ...
m_class = std::make_unique<Class>(data3);
}
bool hasInnerObj() const {
return m_class; // or: return m_class != nullptr;
}
/** call this function only if hasInnerObj() returned true */
Class& getInnerObj() {
return *m_class;
}
private:
std::unique_ptr<Class> m_class;
};
You have two problems:
Reference class members (i.e. m_class) need to be initialized when object is created.
However, both your Class instances (one in the constructor, and one in SetData) are put on the stack and popped right away, making the reference invalid.
What you need to do is make sure that your class object actually lives through the function call. One way of achieving that is allocating it prior to passing it to the OtherClass constructor or SetData function:
class Class {};
class OtherClass
{
public:
OtherClass(Class& c) : m_class(c){}
inline void SetData(Class& c)
{
m_class = c;
}
protected:
private:
Class& m_class;
};
int main()
{
Class a;
OtherClass c(a);
Class b;
c.SetData(b); // changes m_class
return 0;
}
Live example here.

How to do lazy construct in C++?

I want to make 'lazy construct' in a C++ class, a simple method to do that is something like this:
#include "b.hpp" // class B
class A {
public:
// invoke B() in b.hpp, this constructor do not actually do init
A(int v_in) : v(v_in) {}
void foo() {
if(flag == false) {
b = create_B_obj();
flag = true;
}
}
private:
B create_B_obj() {
// some expensive ops
//...
}
private:
bool flag = false;
B b;
int v;
};
But a existing problem is that B may not contain a default constructor (B()), so how can I do 'lazy construct' in this case?
BTW: class B in my project is something like a socket which need to do connect or do bind-like calls, so I want to put these expensive ops lazy.
Use pointer, preferably smart pointer.
class A
{
public:
void foo() {
if( pb == nullptr ) {
pb.reset(create_B_obj());
}
}
private:
B* create_B_obj(); //or return std::unique_ptr
private:
std::unique_ptr<B> pb;
int v;
};
You could avoid the dynamic allocation if you use placement-new instead, in which case you need custom deleter with std::unique_ptr:
class A
{
public:
void foo() {
if( pb == nullptr ) {
pb.reset(create_B_obj());
}
}
private:
B* create_B_obj()
{
return new (buffer) B( /* arguments */);
}
private:
std::unique_ptr<B, PlacementNewDeleter> pb;
alignas(B) char buffer[sizeof(B)]; //buffer used by placement new
int v;
};
where PlacementNewDeleter defined as:
struct PlacementNewDeleter
{
template<typename T>
void operator(T const *obj) const { obj->~T(); }
};
Hope that helps.
If you don't have access on the B class, then the easier way to do this is to use a pointer.
std::unique_ptr<B> b;
Then if your foo method:
B foo()
{
if (! b)
b.reset(new B(/* params */));
// or b.reset(create_B_obj());, which should return a pointer (may also return an unique_ptr)
return b;
}
The std::unique_ptr overloads operator bool and manages the memory so you don't have to delete.
Note: I changed the return type of the foo method as it seems more logical like this.

Nested Classes in c++

class A{
public:
template<typename Obj>
class MyVec{
//some methods...
};
MyVec<A> a; //-> doesnt work
//vector<A> a; //using stl vector-> this works
};
class B{
public:
void someMethod();
private:
A::MyVec<A> b;
};
In the method, when I do sth like:
void someMethod(){
//...
b[0].a.pushback(element);
//...
}
In class A if i use std::vector everything works properly. But when i use nested class it doesn't work.
I've taken your code and modified it as minimally as possible to get something that compiles. This seems to work fine. And so the error is not in the code you have shown us.
#include <iostream>
#include <string>
class A
{
public:
template<typename Obj>
class MyVec{
public:
//My pushback just stores the value away for later.
void pushback(Obj & o )
{
if( obj )
{
*obj = o;
}
else
{
obj = new Obj(o);
}
std::cout<<this<<" : Pushing object "<<&o<<std::endl;
}
//some methods...
//My operator[] just returns the stored object.
Obj& operator[](int i) { return *obj; }
Obj * obj;
MyVec() : obj( NULL ) {}
};
MyVec<A> a;
};
class B
{
public:
B()
{
A an_a;
b.pushback(an_a); //Better store one away since we access it in someMethod.
}
void someMethod()
{
//...
A element;
b[0].a.pushback(element);
//...
}
private:
A::MyVec<A> b;
};
int main()
{
//Test that it all works
B outer;
outer.someMethod();
}
When I run this I get:
0xbffffa5c : Pushing object 0xbffffa0c
0x3ec3c0 : Pushing object 0xbffffa2c
Which is what I'd expect. (one push in the constructor of B and one push to the internal object from someThing)
You can view the result here:
http://ideone.com/BX8ZQ
You really should show the code inside MyVec. As a first guess, maybe MyVec's operator[] isn't returning a reference, so when you do b[0].pushback you're changing a copy instead of what you want; you wouldn't get that problem if you just tested with b.pushback()...