This sounds simple, but right now I am utterly confused. How can I prevent an instance of a class to go out of scope without including the class definition in my header file? Can I use some kind of forward reference. I use C++ VS2017. I hope that the following pseudo-code makes my intention clear.
// MyHeader.h
class X
{
class ThirdPartyClass &tpc; // This must require a forward definition
// and many other things
}
// My program
#include "MyHeader.h"
int main ()
{
X x;
foo(x);
}
// A separately compiled module
#include "MyHeader.h"
#include "ThirdPartyClass.hpp" // (Very large)
void foo (class X &x)
{
ThirdPartyClass localtpc;
x.tpc = &localtpc;
}
I know it won't win a trophy for best code. What I want to do is keeping the instance of localtpc in memory after foo() exits. ThirdPartyClass.hpp is enormous and I don't want to include ThirdPartyClass.hpp in my MyHeader.h. Using a void * to hold a reference does not work, the instance of localtpc gets destructed. ThirdPartyClass maintains a reference count, but it cannot be explicitly manipulated.
Any insight would be greatly appreciated.
HJB
The first thing to note here is that since you've defined tpc as a reference, it must be initialized (not just assigned to), so something even on the general order of x.tpc = &localtpc; just won't work.
As to what will work, I can see (at least) two obvious possibilities. One creates a single instance of ThirdPartyClass, and then initializes all the X objects to contain pointers to that single instance:
// X.h
class X {
ThirdPartyClass &x;
public:
X();
};
// X.cpp
#include "ThirdPartyClass.hpp"
X::X()
: x(holder())
{}
ThirdPartyClass &holder() {
static ThirdPartyClass foo;
return foo;
}
The other obvious possibility would be to use new to create an instance, and initialize your reference from there:
// X.h
class X {
ThirdPartyClass &x;
public:
X();
};
// X.cpp
#include "ThirdPartyClass.hpp"
X::X()
: x(* new ThirdPartyClass)
{}
As to which is preferred: it really depends on how you're using things. If you expect all instances of x to share a single instance of ThirdPartyClass, so (for example) a modification via one should be reflected in all the others, then you almost certainly want something at least vaguely similar to the former.
On the other hand, if each instance of x is expected to have a unique instance of ThirdPartyClass, then you almost certainly want something more like the latter.
Related
I have one class "A" that contains some field, one of these fiels is a class "Z", so I want to send data from this field(which is a class) to the class "A", when I tried to send data from the class "A" to the "Z" via reference it worked, but now I can't see how can I process data in the reverse way.
here's the code:
#ifndef SCREEN_AGENDAVIEW_HPP
#define SCREEN_AGENDAVIEW_HPP
#include <gui_generated/screen_agenda_screen/Screen_agendaViewBase.hpp>
#include <gui/screen_agenda_screen/Screen_agendaPresenter.hpp>
#include <string>
class Screen_agendaView : public Screen_agendaViewBase
{
public:
Screen_agendaView();
virtual ~Screen_agendaView() {}
void Open_Container()override;
void SendToView(std::string text);
protected:
CustomContainer_event ce;
};
#endif // SCREEN_AGENDAVIEW_HPP
#include <gui/screen_agenda_screen/Screen_agendaView.hpp>
Screen_agendaView::Screen_agendaView():ce(*this)
{
}
void Screen_agendaView::Open_Container()
{
customContainer_event1.setVisible(true);
customContainer_event1.invalidate();
}
void Screen_agendaView::SendToView(std::string text)
{
Unicode::snprintf(textArea1Buffer, TEXTAREA1_SIZE, "%s", text);
textArea1.setWildcard(textArea1Buffer);
textArea1.invalidate();
}
#ifndef CUSTOMCONTAINER_EVENT_HPP
#define CUSTOMCONTAINER_EVENT_HPP
#include <gui_generated/containers/CustomContainer_eventBase.hpp>
#include <gui/screen_agenda_screen/Screen_agendaView.hpp>
#include <string>
class CustomContainer_event : public CustomContainer_eventBase
{
public:
//CustomContainer_event();
CustomContainer_event(Screen_agendaView& d);
virtual ~CustomContainer_event() {}
virtual void initialize();
void Save_Note()override;
protected:
int pos_cursor = 0, shif = 1;
Screen_agendaView& s;
std::string text;
};
#endif // CUSTOMCONTAINER_EVENT_HPP
CustomContainer_event::CustomContainer_event(Screen_agendaView& s):s(s)
{
}
void CustomContainer_event::initialize()
{
CustomContainer_eventBase::initialize();
flexButton_Shift.setPressed(true);
}
void CustomContainer_event::Save_Note()
{
for (int i = 0; i <= pos_cursor; i++)
text += textArea2Buffer[i];
s.SendToView(text);
}
OP could pass class A's this (as pointer) or *this (as reference) to the constructor of the member var. of type class Z. Hence, class Z could store this pointer or reference as member itself and use it for accessing its "parent" class A instance.
Demo:
#include <iostream>
struct A; // forward declaration
struct Z {
A &a; // Z holds a reference to the associated instance of A
Z(A &a): a(a) { } // the associated instance of A is passed in constructor
void call(); // cannot be implemented before A became a complete type
};
struct A {
Z z; // A has a member var. of `struct Z` to which it will be associated
A(): z(*this) { } // A passes *this (the reference of its own) to z
void callZ()
{
std::cout << "A::callZ() called.\n";
z.call();
}
void call()
{
std::cout << "A::call() called.\n";
}
};
// now A is complete and Z::call() can use it to access (public) members of A &a
void Z::call()
{
std::cout << "Z::call() called.\n";
a.call();
}
int main()
{
A a;
a.callZ();
}
Output:
A::callZ() called.
Z::call() called.
A::call() called.
Live Demo on coliru
A class which stores a reference to another instance doesn't come without dangers. When such relations are designed then the (human) author should have the intended life-times in mind.
In this case, struct Z will be used as member of struct A exclusively. So, the associated instance of A will outlive it's member z.
If an instance of a class stores the reference to another instance which is destroyed before the first then the reference (inside the first) becomes dangling (i.e. referencing something which isn't existing anymore). As long as the reference isn't used nothing bad will happen. But accessing the dangling reference is Undefined Behavior. (It could crash or cause strange effects or (most accidental case) seem to work until something strange happens later.)
Example for wrong usage:
int main()
{
A *pA = new A();
Z z(*pA);
z.call(); // That's OK.
delete pA;
z.call(); // :-O BAD! z will call z.a.call() although z.a became dangling!
}
This design may cause an additional issue because struct A has to know struct Z to access its members and struct Z has to know struct A. That's a hen-egg-problem and C++ isn't the only effected language.
The solution is a forward declaration, in the above sample
struct A; // forward declaration
A forward declaration forms an incomplete type. It can be used to declare pointers and references. Pointers and references of incomplete types may be used only with certain constraints. E.g. sizeof of the pointer to an incomplete type is allowed because it actually doesn't depend on the type itself. (Pointers have always the same size.) In opposition, accessing the pointee of an incomplete type is not possible (as the pointee is of incomplete type and its contents simply not known as long as the type is incomplete).
Circular dependencies may require that declaration and definition of member functions are separated. In the above sample, it is remarked for Z::call():
// now A is complete and Z::call() can use it to access (public) members of A &a
void Z::call()
{
std::cout << "Z::call() called.\n";
a.call();
}
Defining classes in headers (as it is usual in C++ projects) may cause the issue of circular header dependencies.
If a.h declares struct A and z.h declares struct Z one might be attempted to #include "z.h" in a.h as well as #include "a.h" in z.h. This doesn't work. Either this will lead to a recursion or the author was clever enough to use header guards (to prevent duplicated definitions). In the latter case, one of the two involved headers will finally try to use the declaration of the other class in its own declaration and fail.
The solution is again a forward declaration of one involved class in the header of the other instead of the resp. #include. Both C++ sources may then include both header files without harm and provide the implementations which are based on both classes. This will, of course, require that the implementation of the resp. methods isn't done inline but separately done in the C++ source.
I cannot figure a way to do this in the general case. Say that I have 2 classes and they maintain pointers to each other:
class first {
unique_ptr<second> p2;
public:
first() : p2(this) {}
};
class second {
first* p1;
public:
second(first* arg) : p1(arg) {}
};
This all works fine and dandy, but what I really want is to use a shared_ptr as a part of second because second objects may also be created independently of first. They will just be passed a pointer to a first on construction, but they won't know if it's gone.
I can't just make second::p1 a shared_ptr because I wouldn't know how to pass in this from first::first().
Is there an idiom that can help me handle this?
It is possible with the caveat that you can then only create instances on the heap. Using std::shared_from_this would be a nice solution but it can only be called once a std::shared_ptr to the object exists which is not possible until the constructor has finished, even when using std::make_shared and a std::bad_weak_ptr exception is thrown.
Instead we ensure that the only way to create an instance of this class is through a static function which does the necessary setup.
#include <cassert>
#include <memory>
class second;
class first {
struct Unconstructable {};
std::unique_ptr<second> p2;
public:
first(Unconstructable) : p2() {}
static std::shared_ptr<first> create() {
Unconstructable u;
auto f = std::make_shared<first>(u);
f->p2 = std::make_unique<second>(f);
return f;
}
};
class second {
std::shared_ptr<first> p1;
public:
second(std::shared_ptr<first> arg) : p1(arg) {}
};
int main()
{
auto f = first::create();
}
Edit: The use of Unconstructable isn't really necessary but is required for the use of std::make_unique. If I were to simple make the constructor private then std::make_unique would fail to compile even if I made it a friend function since the implementation uses internal helper functions. Having a private struct as a constructor argument is a way to bypass this while still preventing construction from happening outside of the class itself.
Copying from my comments as OP indicated this is an answer he is OK with.
Unfortunately, there is no safe way of doing so - for the simple matter of constructor not having a slightest idea how an object was allocated. What if it was not allocated dynamically at all?
enable_shared_from_this, as indicated in another comment, is not a solution either - it just allows to get a shared_ptr from a weak_ptr hidden inside the class. However, this is only safe as long as there is at least one shared_ptr already created and holding the lock - and again, this is not something which can be ensured from the constructor.
Regarding the following, are there any reasons to do one over the other or are they roughly equivalent?
class Something
{
int m_a = 0;
};
vs
class Something
{
int m_a;
Something(int p_a);
};
Something::Something(int p_a):m_a(p_a){ ... };
The two code snippets you posted are not quite equal.
class Something
{
int m_a = 0;
};
Here you specify the value with which to initialise, i.e. 0, at compile time.
class Something
{
int m_a;
Something(int p_a);
};
Something::Something(int p_a):m_a(p_a){ ... };
And here you do it at run time (or possibly at run time), with the value p_a not known until the constructor is called.
The following piece of code comes closer to your first example:
class Something
{
int m_a;
Something();
};
Something::Something() : m_a(0) { /* ... */ };
What you have to consider here is that in the first case, the value appears directly in the class definition. This may create an unnecessary dependency. What happens if you need to change your 0 to 1 later on? Exposing the value directly in the class definition (and thus, usually, in a header file) may cause recompilation of a lot of code in situations where the other form of initialisation would avoid it, because the Something::Something() : m_a(0) part will be neatly encapsulated in a source file and not appear in a header file:
// Something.h - stable header file, never changed
class Something
{
int m_a;
Something();
};
// Something.cpp - can change easily
Something::Something() : m_a(0) { /* ... */ };
Of course, the benefits of in-class initialisation may vastly outweigh this drawback. It depends. You just have to keep it in mind.
The first form is more convenient if you have more than one constructor (and want them all to initialise the member in the same way), or if you don't otherwise need to write a constructor.
The second is required if the initialiser depends on constructor arguments, or is otherwise too complicated for in-class initialisation; and might be better if the constructor is complicated, to keep all the initialisation in one place. (And it's also needed if you have to support pre-C++11 compilers.)
The first form is new to C++11 and so at this point isn't terribly well supported, especially if you need to support a variety of older compilers.
Otherwise they should be roughly equivalent when a C++11 compiler is available.
Elaborating on Christian Hackl's answer.
The first form allows to initialize m_a and have a default c'tor at the same time. Or you can even be explicit in your code and define a constructor with the default keyword:
class Something
{
int m_a = 0;
// explicitly tell the compiler to generate a default c'tor
Something() = default;
};
With the second form, an auto-generated default c'tor would leave m_a uninitialized, so if you want to initialize to a hard-coded value, you have to write your own default c'tor:
class Something
{
int m_a;
// implement your own default c'tor
Something() : m_a(0) {}
};
class Something
{
int m_a = 0;
};
is equivalent to
class Something
{
int m_a(0);
};
So, doing
class Something
{
int m_a;// (0) is moved to the constructor
public:
Something(): m_a(0){}
};
yields a uniform syntax for initialization that requires or does not require run-time input.
Personally I don't like the first form because it looks like an "declaration then assignment", which is complete misconception.
If you change the code like what Christian did to make them do the same thing. Now it is a tradeoff between compile-time optimization (which Christian explained completely) and run-time optimization.
class Foo{
public:
Vector<double> vec1;
.
.
.
Vector<double> vecN;
}
Imagine you have to initialize each vector by some predefined doubles. If the program must instantiate many and many objects of this class, it is better to initialize the vectors in the header file to make the user happy by reducing the run-time!
Even though it's supported, this type of initialization will create bugs that will be pretty hard to track down. It's the type of "aesthetic optimization" that you will regret a couple months down the road.
See the example below:
class_x_1.h:
class X
{
private:
int x = 10;
public:
int GetX();
};
class_x_2.h:
class X
{
private:
int x = 20;
public:
int GetX();
};
class_x.cpp:
#include "class_x_1.h" // implementation uses the version that initializes x with 10
int X::GetX()
{
return x;
}
main.cpp:
#include "class_x_2.h" // main includes definition that initializes x with 20
#include <iostream>
int main()
{
X x;
std::cout << x.GetX() << std::endl;
return 0;
}
Output:
20
As expected, it will return 20 because this is the version that initializes x with 20. However, if you go to the implementation of X, you might expected it to be 10.
I'm developing a class for my AVR cpu.
The class is going to handle all port related operations like Set, Read, etc;
Constructor looks like:
(...)
public:
Port(volatile uint8_t * DDR, volatile uint8_t * PORT);
(...)
And it is constructed at the beginning of the main():
int main()
{
Port PortA(&DDRA, &PORTA);
(...)
}
Now I want to make sure that nowhere else in the program object with same parameters would be constructed. It is sure that I cannot create array or map to find it out and throw an exception. It must be done at compile time. So basicly I want to force avr-g++ to check if any other Port(the same first parameter OR the same second parameter) exists in current project.
All functions uses pointers / references to Port objects.
How about the following?
The address of the pointers has to be known at compile-time.
template<int *p>
class Tester
{
public:
static Tester& GetInstance()
{
static Tester t;
return t;
}
private:
Tester() {}
};
int i;
int main()
{
Tester<&i>& t = Tester<&i>::GetInstance();
}
If you only want one instance of a class, then why use classes? The whole purpose of classes, is that you can have multiple intances. Just stick to global variables and free functions.
This is not pretty, but it does get the job done. 10 years experience says embedded work tends to be like this at times. :/
I tested this with a simple class under MSVC, you'll have to adapt for your needs, but it does demonstrate the principle.
Declare your class like this in the header:
class t
{
public:
#ifdef ALLOW_CTOR
t(int i);
~t();
#endif
int get();
private:
int m_i;
};
Then in exactly one file add the line:
#define ALLOW_CTOR 1
include the header file, declare your port instances as file scope variables, and then implement all the class methods of your class, ctor, dtor, accessors, etc.
If you do not place ALLOW_CTOR line in other source files, they can still use the accessor methods in your class, but they can't use the constructor. In the absence of the correct constructor, MSVC complains because it tries to use the default copy constructor, but since the parameter lists don't match, it fails. I suspect the compiler you're using will fail in some way, I'm just not sure exactly what the failure will be.
#Neil Kirk
If failure to provide a declaration of a ctor at all for a compilation unit leads to undefined behavior, then there are ways to solve that.
class t
{
#ifdef ALLOW_CTOR
public:
#else
private:
#endif
t(int i);
public:
~t();
int get();
private:
int m_i;
};
marks the ctor as public in one, but private in all other compilation units, leading to a well defined error: the inability to access a private member function.
Lets say with have generic code like the following:
y.hpp:
#ifndef Y_HPP
#define Y_HPP
// LOTS OF FILES INCLUDED
template <class T>
class Y
{
public:
T z;
// LOTS OF STUFF HERE
};
#endif
Now, we want to be able to use a Y in a class (say X) we create. However, we don't want users of X to have to include the Y headers.
So we define a class X, something like this:
x.hpp:
#ifndef X_HPP
#define X_HPP
template <class T>
class Y;
class X
{
public:
~X();
void some_method(int blah);
private:
Y<int>* y_;
};
#endif
Note that, because y_ is a pointer, we don't need to include its implementation.
The implementation is in x.cpp, which is separately compiled:
x.cpp:
#include "x.hpp"
#include "y.hpp"
X::~X() { delete y_; }
void X::someMethod(int blah) { y_->z = blah; }
So now our clients can just include "x.hpp" to use X, without including and having to process all of "y.hpp" headers:
main.cpp:
#include "x.hpp"
int main()
{
X x;
x.blah(42);
return 0;
}
And now we can compile main.cpp and x.cpp separately, and when compiling main.cpp I don't need to include y.hpp.
However with this code I've had to use a raw pointer, and furthermore, I've had to use a delete.
So here are my questions:
(1) Is there a way I could make Y a direct member (not a pointer to Y) of X, without needing to include the Y headers? (I strongly suspect the answer to this question is no)
(2) Is there a way I could use a smart pointer class to handle the heap allocated Y? unique_ptr seems like the obvious choice, but when I change the line in x.hpp
from:
Y<int>* y_;
to:
std::unique_ptr< Y<int> > y_;
and include , and compile with c++0x mode, I get the error:
/usr/include/c++/4.4/bits/unique_ptr.h:64: error: invalid application of ‘sizeof’ to incomplete type ‘Y<int>’
/usr/include/c++/4.4/bits/unique_ptr.h:62: error: static assertion failed: "can't delete pointer to incomplete type"
so is there anyway to do this by using a standard smart pointer instead of a raw pointer and also a raw delete in a custom destructor?
Solution:
Howard Hinnant has got it right, all we need to do is change x.hpp and x.cpp in the following fashion:
x.hpp:
#ifndef X_HPP
#define X_HPP
#include <memory>
template <class T>
class Y;
class X
{
public:
X(); // ADD CONSTRUCTOR FOR X();
~X();
void some_method(int blah);
private:
std::unique_ptr< Y<int> > y_;
};
#endif
x.cpp:
#include "x.hpp"
#include "y.hpp"
X::X() : y_(new Y<int>()) {} // ADD CONSTRUCTOR FOR X();
X::~X() {}
void X::someMethod(int blah) { y_->z = blah; }
And we're good to use unique_ptr. Thanks Howard!
Rationale behind solution:
People can correct me if I'm wrong, but the issue with this code was that the implicit default constructor was trying to default initialize Y, and because it doesn't know anything about Y, it can't do that. By explicitly saying we will define a constructor elsewhere, the compiler thinks "well, I don't have to worry about constructing Y, because it's compiled elsewhere".
Really, I should have added a constructor in the first place, my program is buggy without it.
You can use either unique_ptr or shared_ptr to handle the incomplete type. If you use shared_ptr, you must outline ~X() as you have done. If you use unique_ptr you must outline both ~X() and X() (or whatever constructor you're using to construct X). It is the implicitly generated default ctor of X that is demanding a complete type Y<int>.
Both shared_ptr and unique_ptr are protecting you from accidentally calling delete on an incomplete type. That makes them superior to a raw pointer which offers no such protection. The reason unique_ptr requires the outlining of X() boils down to the fact that it has a static deleter instead of dynamic deleter.
Edit: Deeper clarification
Because of the static deleter vs dynamic deleter difference of unique_ptr and shared_ptr, the two smart pointers require the element_type to be complete in different places.
unique_ptr<A> requires A to be complete for:
~unique_ptr<A>();
But not for:
unique_ptr<A>();
unique_ptr<A>(A*);
shared_ptr<A> requires A to be complete for:
shared_ptr<A>(A*);
But not for:
shared_ptr<A>();
~shared_ptr<A>();
And finally, the implicitly generated X() ctor will call both the smart pointer default ctor and the smart pointer dtor (in case X() throws an exception - even if we know it will not).
Bottom line: Any member of X that calls a smart pointer member where the element_type is required to be complete must be outlined to a source where the element_type is complete.
And the cool thing about unique_ptr and shared_ptr is that if you guess wrong on what needs to be outlined, or if you don't realize a special member is being implicitly generated that requires a complete element_type, these smart pointers will tell you with a (sometimes poorly worded) compile time error.
1) You are right, the answer is "no": compiler should know the size of member-object, and it cannot know it without having definition of Y type.
2) boost::shared_ptr (or tr1::shared_ptr) doesn't require complete type of object. So if you can afford overhead implied by it, it would help:
The class template is parameterized on T, the type of the object pointed to. shared_ptr and most of its member functions place no requirements on T; it is allowed to be an incomplete type, or void.
Edit: have checked unique_ptr docs. Seems you can use it instead: just be sure that ~X() is defined where unique_ptr<> is constructed.
If you don't like the extra pointer necessary to use the pimpl idiom, try this variant. First, define X as an abstract base class:
// x.hpp, guard #defines elided
class X
{
protected:
X();
public:
virtual ~X();
public:
static X * create();
virtual void some_method( int blah ) = 0;
};
Note that Y doesn't feature here. Then, create an impl class which derives from X:
#include "Y.hpp"
#include "X.hpp"
class XImpl
: public X
{
friend class X;
private:
XImpl();
public:
virtual ~XImpl();
public:
virtual void some_method( int blah ) = 0;
private:
boost::scoped_ptr< Y< int > > m_y;
};
X declared a factory function, create(). Implement this to return an XImpl:
// X.cpp
#include "XImpl.h"
X * X::create()
{
return new XImpl();
}
Users of X can include X.hpp, which has no inclusion of y.hpp. You get something which looks a little like pimpl, but which doesn't have the explicit extra pointer to an impl object.