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.
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.
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.
When you use a unique_ptr<T> for a forward declared type T, the unique_ptr destructor requires the T is complete, but the move assignment operator as well (and reset), according to this table:
https://stackoverflow.com/a/6089065/1794803
So, for your pImpl idiom, to implement it correctly, you have to declare the delete and the move assignment method (which, as side effect, marks them non-inlined):
class impl_t;
class A
{
std::unique_ptr<impl_t> p_impl;
public:
// Implement in A.cpp as A::~A() = default;
~A();
// Implemented in A.cpp as A& operator=(A&&) = default;
A& operator=(A&& he);
};
But, since std::unique_ptr is a RAII-solution for dynamic memory, and you pImpl is already inside a class, and you are forced to write a destructor anyway, isn't it better to just manage a raw pointer, since you class is already a RAII-like from the point of view of p_impl?:
class impl_t;
class A
{
impl_t* p_impl;
public:
~A(); // The destructor must be written anyway.
// The omitted move assignment destructor doesn't cause UB.
};
Isn't that a better solution? (+ defined or delete your own copy/move operator if you want to class is copyable/movable or not; but that is a "conscious choice"; however, don't writting a move assignment for unique_ptr is an error).
Using a unique_ptr only saves you for written a delete p_impl in a destructor that you have to declare anyway.
unique_ptr is an excellent choice for local dynamic objects which will be destructed even in case of exceptions, but for "attributes", you save nothing but the possibility of getting UB if you don't remember you have to rewrite the move assignment operator.
Well, using a std::unique_ptr redeems you from bothering with the explicit delete for the p_impl.
Also it should work well in cases of concurrent access and exceptional cases in the constructor (which doesn't seem to be guaranteed using a raw pointer and new yourself).
std::unique_ptr should be the preferred way for pimpl according. For reference, see Herb Sutter's talk at CppCon16 at around 10mins.
The reason is, it will prevent you from accidently changing your pimpl while maintining RAII.
In the question, the not needing to define a move assignment operator is given as a desired advantage. Below I suggest yet another solution that ‘also’ has this advantage, plus that you don’t need to define the destructor. Still I think the most important advantage of the solution below is that the implementation can now be defined in an anonymous namespace (or unnamed namespace).
The price you have to pay is the declaration of a (reusable) base class: impl_t.
#include <iostream>
#include <memory>
////////////////////////
// a utility impl.h file
struct impl_t
{
virtual ~impl_t() = 0;
};
inline impl_t::~impl_t() {}
///////////////////////
// the a_class.cpp file
class a_class_t
{
std::unique_ptr<impl_t> m_pimpl;
public:
a_class_t();
int a_method(int);
};
///////////////////////
// the a_class.cpp file
namespace { // anonymous
struct a_class_impl_t
: impl_t
{
int a_method(int x)
{
return x + 1;
}
~a_class_impl_t()
{
std::cout << "~a_class_impl_t()\n";
}
};
} // anonymous namespace
int a_class_t::a_method(int x)
{
return dynamic_cast<a_class_impl_t&>(*m_pimpl).a_method(x);
}
a_class_t::a_class_t()
: m_pimpl(std::make_unique<a_class_impl_t>())
{}
////////////////////
// the main.cpp file
int main()
{
a_class_t a_class;
std::cout << a_class.a_method(1) << '\n';
}
And also this solution is best of with a unique_ptr.
If I have a header like this:
#include <vector>
class Data;
class A {
// const Data& getData( int i ) const { return a[i]; }
std::vector<Data> a;
};
the compiler compiles it normally, because it doesn't need to know a bit about Data type.
Retuning a value by reference does not depend on a class implementation and therefore do not require any knowledge of the class internals.
But when I uncomment the accessor compiler starts to complain on invalid use of incomplete type 'class Data'. Why?
So, the C++ Standard is not particularly clear on this point. The problem that you are hitting is whether or not you can instantiate vector<Data> when you Data is not a complete type.
If we look at Section 17.6.4.8 Paragraph 2, we find the following statement:
In particular, the effects are undefined in the following cases:
...
if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
std::vector does not explicitly allow incomplete types for the template argument, so this is technically invalid code.
This would mean that this is invalid code, even if your compiler accepts it.
class Data;
class A {
std::vector<Data> a;
};
Thanks to people reaction I understood the problem better.
It becomes more clear when we rid from std::vector:
class Data;
class A {
const Data& getData( int i ) const { return a[i]; }
Data* a;
};
to return i-th element of array a one needs to know where is it in the memory. For this one needs to know sizeof(Data), which is not possible for incomplete type.
The exactly same problem std::vector should have.
Because knowing that there exists a class Data is not enough to know what std::vector<Data>::operator[](size_t i) should do, or even whether it exists. This is fundamental to the nature of class templates.
It does not require a complete type in the declaration. It requires a complete type before the vector constructor and destructor (or any other members really) are called. This is when the size of the struct or class needs to be defined.
In your code, the A's constructor and Destructor are declared as default, and thus are defined in the header file. The vector cannot allocate or deallocate stuff of a size it does not know, so it barfs. You can solve this by explicitly declaring your destructor and constructor in "A.h", and making sure Data is defined before any of your member functions are defined.
The following code works and is valid.
//"A.h"
class Data; // forward declaration only
class A
{
public:
A();
~A();
const Data& getData( int i ) const;
std::vector<Data> a;
};
//"A.cpp"
#include "A.h"
class Data {int i;}; // actual class here before the definition of A::A(),...
A::A(){}
A::~A(){}
Data& A::getData(int i) const {return a[i];}
I'm working on a class library in VC++ that shall have ref classes and some native code. Now, I need to use five native objects from an external framework. those objects must be declared on the heap NOT on the stack. I want encapsulate those objects in some sort of a structure knowing that constructors need to be called.
Thank you.
I'm not sure I know exactly what you're asking. Constructors always need to be called on objects whether they are on the heap or the stack. If you meant that you want something to automatically call destructors for heap allocated memory, then you can use either std::auto_ptr or boost::shared_ptr. Note that these are not equivalent so read the documentation! Auto pointers cannot be used in standard containers as they do not have the copy semantics necessary, while boost::shared_ptr can as it counts references as it copies.
To answer your more general question of declaration best-practices, you want to only fully declare objects that you need to and forward declare when you can. For example, if you have a class like:
// In X.h
class MyConfig;
class X
{
X(const MyConfig &config);
private:
const MyConfig &config;
};
// In X.cpp
#include "MyConfig.h"
X::X(const MyConfig &config) : config(config)
{
}
Here you do not need to full declaration contained in MyConfig.h within the X.h header file. You can do this b/c you do not need to know the size of the MyConfig object to construct class X as it only contains a reference which is the same size regardless of what the underlying object is. Doing this will help with dependencies and will also reduce compile times.
If on the other hand the private member config was changed to const MyConfig x; then you would have to include the MyConfig.h header in X.h because to construct class X requires knowledge of how much memory to allocate to store a MyConfig object.
Well, for each unmanaged class X, declare a ref class XWrapper that stores the unmanaged pointer to X privately, new's in constructor, and delete's in destructor. Why not?
You should wrap a shared_ptr like this:
template <class T>
class my_object_wrapper
{
boost::shared_ptr<T> ptr; // or std::tr1::shared_ptr<T> if available
public:
my_object_wrapper()
: ptr(new T)
{
}
boost::shared_ptr<T> ptr() const { return ptr; }
}
You could also use the pheonix approach:
template <class T>
class my_object_wrapper
{
boost::shared_ptr<T> ptr; // or std::tr1::shared_ptr<T> if available
public:
my_object_wrapper()
{
}
boost::shared_ptr<T> ptr()
{
if (ptr == null)
ptr = new T;
return ptr;
}
}