I need a parent class to have a pointer to a child class' struct member. Is it possible to solve this during initialization as shown below, or will the address to _foo not be available/be invalid?
struct Foo { int a; int b; }
class A {
public:
A(void* fooHandle) : _fooHandle(fooHandle) {}
private:
void* _fooHandle;
};
class B : public A {
public:
B() : A(&_foo) {
/* _foo initialized here */
}
private:
Foo _foo;
};
Is this code safe? I.e. will &_foo give a valid address? Of course I mean according to the standard, not whether it may work for some compilers.
Yes, this is perfectly safe.
EDIT (explanation): The storage for the object is allocated before any constructor is called. Objects occupy a region of storage that has one start and one end address. There may be gaps inbetween (padding). However for the whole lifetime of an object, all it's members are alive as well. When the constructors are called (eventually) all member objects part of the class the constructor of which is called, already live (by constructor I mean the part between {…}). This is why, if you need initialization before constructor execution you have to provide initializers. Members are initialized in the order as it appears in the class and you'll get severe warnings if initializers appear in a different order, so as long as you pass addresses to members, which went through initialization, you're within the lifetime of these members.
In the same way the lifetime of members ends only after all destructors were called.
Of course anything created with new and destroyed with delete has lifetimes that are not tied to class instance lifetimes, so you've to be careful with that.
However I wonder what the practical application of this is. Also I'd suggest to use a reference instead of a pointer to enforce passing a valid object and also making the constructor protected, so that it can be used only from child classes.
Related
I know that I need to define a virtual destructor (best option even if my class is final).
In my case, I am using C-like structures (no functions, no defaults, just plain members) and use inheritance to compose a new structure. I then store a pointer to the base class in std::unique_ptr and let RAII do the rest.
I am now curious if there is a need to also explicitely add a virtual destructor to avoid memory problems.
An example might be:
#include <chrono>
#include <memory>
struct A {
std::chrono::milliseconds duration = std::chrono::milliseconds{-1};
int count = 0;
};
struct B {
int mode = 0;
};
struct C : public A, public B {
int foo = 1;
};
int main()
{
std::unique_ptr<A> base = std::make_unique<C>();
base.reset(); // I expect here that A,B and C are destructed properly
return 0;
}
It doesn't matter whether the class is polymorphic or whether it is trivial.
If delete is called on a pointer of different type (up to cv-qualification) than the most-derived type of the object it points to and the pointed-to-type doesn't have a virtual destructor, then the behavior is undefined.
One obvious reason for this rule is that the base class subobject might not be located at the same address as the most-derived object. So the compiler would have no way of knowing what the offset to pass to the deallocation function needs to be.
One could maybe argue that a standard-layout class with trivial destructor would not need to follow this rule if a pointer to the first base class subobject is used, but the standard doesn't make that exception and your class C isn't standard-layout anyway.
See CWG issue 1259 closed as not-a-defect. The size-aware global deallocation functions mentioned in the issue were also introduced with C++14, which is another reason that using a base class pointer may cause you problems in practice, even if the destructor is trivial and the address without offset.
If you use shared_ptr rather than unique_ptr then this will work as the deleter of the shared_ptr is created when the first pointer is created and doesn't change when the pointer is copied between shared_ptr instances. This doesn't apply in unique_ptr which will use std::default_delete<T> where T is the type of the unique_ptr instance not the type originally constructed.
See https://godbolt.org/z/TjP6dbo9G for some examples of unique_ptr failing and shared_ptr working.
I have two classes, Base and Derived. Derived constructs Base using its own member object, which inherits from Base::BaseChild.
struct Base
{
struct BaseChild
{
int x = 5;
};
Base(BaseChild& c): baseData(c), constantVar(c.x)
{
assert(constantVar == 5);
}
int getX() const {return baseData.x;}
private:
const int constantVar;
BaseChild& baseData;
};
struct Derived: public Base
{
struct DerivedChild: public BaseChild
{
double y = 4.0;
};
Derived(): Base(data) {}
private:
DerivedChild data;
};
Derived myObject;
assert(myObject.getX() == 5);
Reasoning: I do this in this way because everything seems pretty encapsulated for my case, where I need to send Childs to swap their content (vector, shared_ptr, unique_ptr) with other Childs, keeping child memory address, and I still can access to Child object from base class without the need of a virtual function, which was killing my app performance.
Question: I've read another post like this one, where it states initialization of a Derived member before the Base isn't possible. So the constantVar assert would always fail. However getX() works fine, after the constructor, and I'm interested in these functions which are called once the constructor ends. Is this safe? Or is there any hidden danger here?
The base class Base of Derived is constructed before the member data.
As a result data will not be initialized when you pass a reference to it to Base's constructor. The initialization will happen after that constructor call.
You are however trying to read the member x of data in Base's constructor. At this point data's lifetime has not started yet and accessing the value of a non-static data member of an object outside its lifetime causes undefined behavior.
Whether or not the assertions succeed isn't significant. Undefined behavior allows for either outcome.
The situation would be potentially different (although technically not rules in the standard) if you were not trying to access the value of data inside Base's constructor, but only storing the reference to it.
I am primarily a c# programmer but a project I am working on has me using c++. In C# I have the ability to define a member of a class where the member is null until it is initialized. Like so:
Class Foo{
private Bar _bar;
public Foo(int valueBarNeeds){
_bar = new Bar(valueBarNeeds);
}
}
The value of _bar is null and access is prohibited until it is initialized. The rationale for this use case is that the constructor for the private object relies on some value that is not known until the parent class is constructed.
Now, in C++ I try and do the same thing:
class Foo{
public:
Foo(int valueBarNeeds){
_bar = new Bar(valueBarNeeds);
}
private;
Bar _bar;
};
The compiler throws an error saying that there is no constructor for bar that takes zero arguments. My understanding is, in C++ the new keyword means something completely different. As a part of this difference, one is able to define objects that get disposed at the end of a method without needing a manual deletion by declaring without the new keyword.
SomeFunc(){
int valueBarNeeds = 100;
Bar _bar(valueBarNeeds);
_bar.SomeFunc();
}
_bar is deleted when the methods stack goes out of scope.
This then sets up my question. If the syntax that I use in C# to create unitialized objects actually tries to initialize objects in C++... How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?
The problem is that what you're calling "initialisation" is actually no such thing. Any members that are initialised, implicitly or explicitly, are initialised before the program enters your constructor body.
Your code snippets show only assignment; it doesn't matter that you're doing this in the body of a constructor for the encapsulating object. It's still just assignment.
Bar is a class so your member _bar will be implicitly initialised, but it actually cannot be because the class has no constructor taking no arguments. In order to provide arguments, you have to explicitly initialise the member yourself.
In C++ we initialise members like this:
class Foo {
public:
Foo(int valueBarNeeds)
: _bar(valueBarNeeds)
{}
private:
Bar _bar;
};
You are also right in that you are misunderstanding new a little; unlike in Java, it should be used sparingly, as objects are fundamentally created by simply declaring (and, where necessary, defining) them. The use of new is reserved for dynamic allocation in the free store and returns a pointer for use; this usage should be rare. You successfully fixed this in your final code snippet.
How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?
If the member is of a class type, it will always be initialised. You can't have an object that doesn't exist. The closest you can get is to encapsulate a pointer rather than an object:
class Foo {
public:
Foo(int valueBarNeeds)
: _bar(nullptr)
{
// some time later...
_bar = new Bar(valueBarNeeds);
}
private:
Bar* _bar;
};
But this opens up a can of worms as regards memory management and whatnot and, as explained above, you should avoid it unless you really need it. Alternatives include smart pointers but you should still consider sticking with the bog-standard object encapsulation where possible. It should be rare that you need to deliberately leave an object in an invalid state for a time.
You give your class a data member of that type, and initialize it in the constructor's initialization list:
class Foo
{
public:
Foo(int valueBarNeeds) :_bar(valueBarNeeds) {}
private:
Bar _bar;
};
Once you are in the constructor's body, all data members have been initialized. If you do not initialize them explicitly in the constructor initialization list, they get default initialized, which means the default constructor is called for user defined types, and no initialization is performed for built-in types.
I want to define the object of a class within a structure and access function members of the class. Is it possible to achieve this?
With the following code I am getting a segmentation fault at ps_test->AttachToInput(2145);. I can't figure out the reason, everything looks correct to me:
class test
{
public:
test();
virtual ~test();
int init_app(int argc, char* argv[]);
virtual void AttachToInput(int TypeNumber, int DeviceNo=0);
}
struct capture
{
test h_app;
gint port;
};
main()
{
struct capture h_cap;
test *ps_test = &h_cap.h_app;
ps_test->AttachToInput(2145);
}
First of all, the only difference between a class and a struct in C++ is that a class' members are private by default and a struct's members are public by default. Compiler-generated ctors and dtors are visible in both cases - unless otherwise stated by the programmer (e.g. they move the default ctor into a private section). Otherwise construction and destruction of instances of user-defined types marked class wouldn't be possible without explicit, public declaration - thus defying the very purpose of compiler-generated functions.
So basically, what you do in your example is merely composition of two user defined types which is perfectly legal. When you create an instance of capture, an instance of test is created as well.
What you can't do is publicly access AttachToInput() from outside of test and derived types of test. You need to declare the function public in order for this line to compile:
h_cap.h_app.AttachToInput(); // error: member function of `test` is protected
On another, unrelated note (but I came across it so I mention it), your class test holds a raw pointer to char. Holding raw pointers is ok, if the lifetime of the entity that's being pointed is guaranteed to exceed the lifetime of the object that holds the pointer. Otherwise, it's very likely the object itself is responsible for the destruction of said entity. You need to be sure about who owns what and who's responsible for allocation and deallocation of stuff.
EDIT: It should be noted, that Alan Stokes proposed the same in the comment section while I wrote this answer. :)
EDIT2: Slight oversight, implicit default access is also assumed for base classes depending on how the derived class is declared. See What are the differences between struct and class in C++?.
Say I have:
class A
{
A()
{}
~A()
{}
};
class B
{
public:
B()
{}
~B()
{}
private:
static A mA;
};
B* pB = new B;
delete pB;
When I call delete pB, B's destructor will be called. Will this then call the destructor for static member A?
The keyword static means that the variable is independent of instances. That's why you can access static variables and methods without instantiating an object from the class in the first place. That's why destroying an instance will not affect any static variables.
Of course not. First of all, you've defined an explicit empty destructor. And if the default destructor did that, you could never destruct instances without risking making the class unusable.
C++ Standard 03, 9.4.2 Static data members:
A static data member is not part of
the subobjects of a class. There is
only one copy of a static data member
shared by all the objects of the
class.class.
A static data member is not part of the class -- hence it's not tied to the classes lifetime nor at construction or destruction.
Construction (9.4.2/3)
Once the static data member has been
defined, it exists even if no objects
of its class have been created.of its class have been created.
Destruction (9.4.2/7)
Static data members are initialized and destroyed exactly like non-local objects.
Objects with a static lifetime will be destructed when the application terminates. Among the various static objects that might be in the program, the destructors are called in the reverse order of how the objects were constructed.
The construction/destruction of object instances has no effect on when a static member is constructed or destroyed.
Static members do not live in the memory space assigned to an instance of the class. Therefore, it will not be deleted or deinitialized unless you do it explicitly in any part of your code (including the class destructor, but your code logic must handle the possibility of having multiple instances and so on...)
Static variables is also known as class variables. This is as opposed to instance variables. As these names implies, class variables pertain to the entire class, where as instance variables belong to an instance. One can derive the life span of these variables based on these facts.
Another way to look at this assume calling the destructor actually destroys static variables. Imagine then the consequence of one object gets instantiated and then gets deleted. What would happen the the static variables which are shared by all other objects of the class which are still being in used.