Background: I am a novice in C++. I have a C# project that I want to convert to C++ to gain some experience in writing some useful C++ code, beyond textbook examples. To this end, I have examined the code of some open source projects to get the feel of real C++, and also tried to do some refactoring in a fairly old project with some valgrind action and some adhoc statistics in debug build to confirm correctness (all with real input). (I have done a college project in C++ a number of years ago, but I don't count that as any real experience).
Actual question:
The C# project I am trying to convert to C++ uses lite weight dependency injection. Every class receives a "context" object in the constructor. It first inserts itself into the "context" before querying its own dependencies so that circular dependencies are not a problem.
After some pondering I came up with a following scheme in C++. Every DI object receives its dependencies by reference in the constructor. I make all DI objects fields in one class (by value as sub-objects) and wire them up in the initialization list.
// Yes, the project is compiler for a toy programming language
class Compiler {
Logger log;
Options options;
ParserDriver parserDriver;
DeclarationAnalysis declarationAnalysis;
CodeTypeAnalysis codeTypeAnalysis;
FlowAnalysis flowAnalysis;
CodeGeneration codeGeneration;
Check check;
Typings typings;
Operators operators;
Symtab symtab;
public:
Compiler();
};
Compiler::Compiler() :
log(),
options(),
parserDriver(log),
declarationAnalysis(log, symtab, check),
codeTypeAnalysis(log, symtab, operators, typings, check),
flowAnalysis(log),
codeGeneration(typings, symtab),
check(log, symtab),
typings(symtab),
operators(symtab, log, typings),
symtab()
{}
// Example DI object
class DeclarationAnalysis {
Logger* log;
Symtab* symtab;
Check* check;
public:
DeclarationAnalysis(Logger&, Symtab&, Check&);
}
DeclarationAnalysis::DeclarationAnalysis(Logger& log, Symtab& symtab, Check& chack)
: log(&log), symtab(&symtab), check(&check) {}
Is code like this correct in a sense that it's safe, without undefined behavior (eg. symtab is initialized last but given as argument to other field's constructors)? It seems very elegant at first sight. Memory is packed, can even be allocated on the stack. Have I rediscovered an existing pattern?
Constructor initialization lists are called in order the objects exist in the class. Compilers can be set to warn.if the constructor list is a different order. Turn that on.
You can take references to uninitialized values and pass them around. Anything besides storing a pointer or reference to those uninitialized objects is not a good plan.
In your sample code you are storing pointers only. That is safe.
The destructors of those types cannot assume the pointed-to objects exist, as part way through Compiler construction it could fail (via exception) and cause destruction of the already-constructed subobjects. This is difficult to get right.
Related
Coming from Delphi, I'm used to using class references (metaclasses) like this:
type
TClass = class of TForm;
var
x: TClass;
f: TForm;
begin
x := TForm;
f := x.Create();
f.ShowModal();
f.Free;
end;
Actually, every class X derived from TObject have a method called ClassType that returns a TClass that can be used to create instances of X.
Is there anything like that in C++?
Metaclasses do not exist in C++. Part of why is because metaclasses require virtual constructors and most-derived-to-base creation order, which are two things C++ does not have, but Delphi does.
However, in C++Builder specifically, there is limited support for Delphi metaclasses. The C++ compiler has a __classid() and __typeinfo() extension for retrieving a Delphi-compatible TMetaClass* pointer for any class derived from TObject. That pointer can be passed as-is to Delphi code (you can use Delphi .pas files in a C++Builder project).
The TApplication::CreateForm() method is implemented in Delphi and has a TMetaClass* parameter in C++ (despite its name, it can actually instantiate any class that derives from TComponent, if you do not mind the TApplication object being assigned as the Owner), for example:
TForm *f;
Application->CreateForm(__classid(TForm), &f);
f->ShowModal();
delete f;
Or you can write your own custom Delphi code if you need more control over the constructor call:
unit CreateAFormUnit;
interface
uses
Classes, Forms;
function CreateAForm(AClass: TFormClass; AOwner: TComponent): TForm;
implementation
function CreateAForm(AClass: TFormClass; AOwner: TComponent): TForm;
begin
Result := AClass.Create(AOwner);
end;
end.
#include "CreateAFormUnit.hpp"
TForm *f = CreateAForm(__classid(TForm), SomeOwner);
f->ShowModal();
delete f;
Apparently modern Delphi supports metaclasses in much the same way as original Smalltalk.
There is nothing like that in C++.
One main problem with emulating that feature in C++, having run-time dynamic assignment of values that represent type, and being able to create instances from such values, is that in C++ it's necessary to statically know the constructors of a type in order to instantiate.
Probably you can achieve much of the same high-level goal by using C++ static polymorphism, which includes function overloading and the template mechanism, instead of extreme runtime polymorphism with metaclasses.
However, one way to emulate the effect with C++, is to use cloneable exemplar-objects, and/or almost the same idea, polymorphic object factory objects. The former is quite unusual, the latter can be encountered now and then (mostly the difference is where the parameterization occurs: with the examplar-object it's that object's state, while with the object factory it's arguments to the creation function). Personally I would stay away from that, because C++ is designed for static typing, and this idea is about cajoling C++ into emulating a language with very different characteristics and programming style etc.
Type information does not exist at runtime with C++. (Except when enabling RTTI but it is still different than what you need)
A common idiom is to create a virtual clone() method that obviously clones the object which is usually in some prototypical state. It is similar to a constructor, but the concrete type is resolved at runtime.
class Object
{
public:
virtual Object* clone() const = 0;
};
If you don't mind spending some time examining foreign sources, you can take a look at how a project does it: https://github.com/rheit/zdoom/blob/master/src/dobjtype.h (note: this is a quite big and evolving source port of Doom, so be advised even just reading will take quite some time). Look at PClass and related types. I don't know what is done here exactly, but from my limited knowledge they construct a structure with necessary metatable for each class and use some preprocessor magic in form of defines for readability (or something else). Their approach allows seamlessly create usual C++ classes, but adds support for PClass::FindClass("SomeClass") to get the class reference and use that as needed, for example to create an instance of the class. It also can check inheritance, create new classes on the fly and replace classes by others, i. e. you can replace CDoesntWorksUnderWinXP by CWorksEverywhere (as an example, they use it differently of course). I had a quick research back then, their approach isn't exceptional, it was explained on some sites but since I had only so much interest I don't remember details.
I am practicing dependency injection and there are several issues that i am not sure how to deal with them.
class A may be dependant on 3-4 other behaviour (interfaces). On the one hand, passing all of them in the constructor makes the object harder to create and initialize. On the other hand, using setters might be problematic in case a client forgot to set one of the dependencies. What would be the correct way to deal with this?
Eventually, all dependencies must be created somewhere. How do i prevent a case in which i have many initialization in one class (for example, the main class) ?
Is it considered a good practice to use shared_ptr when doing dependency injection? In such cases the creator of the dependencies usually could not delete the objects, so it makes sense to me to use shared pointers.
class A may be dependant on 3-4 other behaviour (interfaces). On the one hand, passing all of them in the constructor makes the object harder to create and initialize. On the other hand, using setters might be problematic in case a client forgot to set one of the dependencies. What would be the correct way to deal with this?
There's no perfect solution, so you just have to tune to taste. Options include:
having the/a constructor accept a structure grouping the injected objects (if you're passing the same set of dependencies to many constructors)
dividing dependencies between run-time and compile-time and having compile-time dependencies factored using derivation/using/typedef ("Policies" ala Modern C++ Design by Alexandrescu)
providing defaults for some/all dependencies, or some dynamic lookup "service" that still lets you modify the injections but persists across multiple dependent-object constructions
A bit of imagination and analysis of your repetitive code would hopefully suggest an approach to you....
Eventually, all dependencies must be created somewhere. How do i prevent a case in which i have many initialization in one class (for example, the main class) ?
This is a matter of factoring redundant dependency creation and the access to objects - your choices are similar - passing around references or pointers, using structures or containers or management objects to group them and re-access them....
Is it considered a good practice to use shared_ptr when doing dependency injection? In such cases the creator of the dependencies usually could not delete the objects, so it makes sense to me to use shared pointers.
For functions, often the client code necessarily outlives the use by the function being called so there's no need for shared pointers... a reference is ideal. If you're using threads, or creating objects that can outlive the client code, then shared pointers can make a lot of sense.
All personal opinions, but there we go.
1) Pass the dependencies to the constructor. If there are sensible defaults, then provide multiple constructors or use default arguments.
2) If you're going to be using the same set of dependencies frequently, you might be able to save yourself some typing by creating a "dependency set" class, an instance of which can be passed to a constructor, something like:
struct Iface1;
struct Iface2; // Dependent interfaces
struct Iface3;
struct DependencySet
{
Iface1& iface1;
Iface2& iface2;
Iface3& iface3;
};
class Dependent
{
public:
Dependent(DependencySet& set)
: iface1(set.iface1)
, iface2(set.iface2)
, iface3(set.iface3)
{}
private:
Iface1& iface1;
Iface2& iface2;
Iface3& iface3;
};
3) Personally I'd favour using references as above and managing the lifetimes so that the dependencies outlive the dependent class, but shared pointers could be used if you want to "forget" about the dependencies once you've used them.
My understanding is that exposing functions that take or return stl containers (such as std::string) across DLL boundaries can cause problems due to differences in STL implementations of those containers in the 2 binaries. But is it safe to export a class like:
class Customer
{
public:
wchar_t * getName() const;
private:
wstring mName;
};
Without some sort of hack, mName is not going to be usable by the executable, so it won't be able to execute methods on mName, nor construct/destruct this object.
My gut feeling is "don't do this, it's unsafe", but I can't figure out a good reason.
It is not a problem. Because it is trumped by the bigger problem, you cannot create an object of that class in code that lives in a module other than the one that contains the code for the class. Code in another module cannot accurately know the required object size, their implementation of the std::string class may well be different. Which, as declared, also affects the size of the Customer object. Even the same compiler cannot guarantee this, mixing optimized and debugging builds of these modules for example. Albeit that this is usually pretty easy to avoid.
So you must create a class factory for Customer objects, a factory that lives in that same module. Which then automatically implies that any code that touches the "mName" member also lives in the same module. And is therefore safe.
Next step then is to not expose Customer at all but expose an pure abstract base class (aka interface). Now you can prevent the client code from creating an instance of Customer and shoot their leg off. And you'll trivially hide the std::string as well. Interface-based programming techniques are common in module interop scenarios. Also the approach taken by COM.
As long as the allocator of instances of the class and deallocator are of the same settings, you should be ok, but you are right to avoid this.
Differences between the .exe and .dll as far as debug/release, code generation (Multi-threaded DLL vs. Single threaded) could cause problems in some scenarios.
I would recommend using abstract classes in the DLL interface with creation and deletion done solely inside the DLL.
Interfaces like:
class A {
protected:
virtual ~A() {}
public:
virtual void func() = 0;
};
//exported create/delete functions
A* create_A();
void destroy_A(A*);
DLL Implementation like:
class A_Impl : public A{
public:
~A_Impl() {}
void func() { do_something(); }
}
A* create_A() { return new A_Impl; }
void destroy_A(A* a) {
A_Impl* ai=static_cast<A_Impl*>(a);
delete ai;
}
Should be ok.
Even if your class has no data members, you cannot expect it to be usable from code compiled with a different compiler. There is no common ABI for C++ classes. You can expect differences in name mangling just for starters.
If you are prepared to constrain clients to use the same compiler as you, or provide source to allow clients to compile your code with their compiler, then you can do pretty much anything across your interface. Otherwise you should stick to C style interfaces.
If you want to provide an object oriented interface in a DLL that is truly safe, I would suggest building it on top of the COM object model. That's what it was designed for.
Any other attempt to share classes between code that is compiled by different compilers has the potential to fail. You may be able to get something that seems to work most of the time, but it can't be guaraneteed to work.
The chances are that at some point you're going to be relying on undefined behaviour in terms of calling conventions or class structure or memory allocation.
The C++ standard does not say anything about the ABI provided by implementations. Even on a single platform changing the compiler options may change binary layout or function interfaces.
Thus to ensure that standard types can be used across DLL boundaries it is your responsibility to ensure that either:
Resource Acquisition/Release for standard types is done by the same DLL. (Note: you can have multiple crt's in a process but a resource acquired by crt1.DLL must be released by crt1.DLL.)
This is not specific to C++. In C for example malloc/free, fopen/fclose call pairs must each go to a single C runtime.
This can be done by either of the below:
By explicitly exporting acquisition/release functions ( Photon's answer ). In this case you are forced to use a factory pattern and abstract types.Basically COM or a COM-clone
Forcing a group of DLL's to link against the same dynamic CRT. In this case you can safely export any kind of functions/classes.
There are also two "potential bug" (among others) you must take care, since they are related to what is "under" the language.
The first is that std::strng is a template, and hence it is instantiated in every translation unit. If they are all linked to a same module (exe or dll) the linker will resolve same functions as same code, and eventually inconsistent code (same function with different body) is treated as error.
But if they are linked to different module (and exe and a dll) there is nothing (compiler and linker) in common. So -depending on how the module where compiled- you may have different implementation of a same class with different member and memory layout (for example one may have some debugging or profiling added features the other has not). Accessing an object created on one side with methods compiled on the other side, if you have no other way to grant implementation consistency, may end in tears.
The second problem (more subtle) relates to allocation/deallocaion of memory: because of the way windows works, every module can have a distinct heap. But the standard C++ does not specify how new and delete take care about which heap an object comes from. And if the string buffer is allocated on one module, than moved to a string instance on another module, you risk (upon destruction) to give the memory back to the wrong heap (it depends on how new/delete and malloc/free are implemented respect to HeapAlloc/HeapFree: this merely relates to the level of "awarness" the STL implementation have respect to the underlying OS. The operation is not itself destructive -the operation just fails- but it leaks the origin's heap).
All that said, it is not impossible to pass a container. It is just up to you to grant a consistent implementation between the sides, since the compiler and linker have no way to cross check.
OS : xp
IDE : VS 2008
In the project that i'm doing in visual C++ i have declared a std::vector inside managed class as so
std::vector<pts> dataPoints;//this gives error c4368 : mixed type not allowed
but this works
std::vector<pts> * dataPoints;//a pointer to the vector
i then have created this vector on the free store as so in the constructor of the managed class
dataPoints = new std::vector<pts>(noOfElements,pts());//which is not so attractive.
the reason i need vector is because there is file that i'm reading through the ifstream and storing those values in the vector.
Q1) why is that i'm able to declare a pointer to object of native type(i guess)but not an object?
furthermore, prior to trying vector i tried the managed array as so
cli::array<Point> dataPoints //and i defined it later.
but when i do this
ifile >> dataPoints[i].X;
it gives an error c2678 : operator= is not overloaded for int!!.
Q2) why is it that i cant use a managed code here. At first i thought it might be a wrapper class Int but then autounboxing(conversion operators) should take care of it?or is it that Point::X is qualified with property and thus is not recognized as normal int? what am i missing?.
this is the reason i went for vector and pts solution.
pts is as follows
struct pts
{
int X, int Y;
pts() : X(0),Y(0){}
pts(int x,int y) : X(x),Y(y){}
};//this i created to store the data from the file.
An important property of managed class objects is that they get moved by the garbage collector. This happens when it compacts the heap. That plays havoc with native C++ objects, pointers to their members will become invalid. So as a rule, the compiler forbids embedding a native non-POD object inside a managed one. A pointer is not a problem.
The exact same problem exists for your use of the >> operator. The int gets passed by reference to operator>>(). Disaster strikes if the garbage collector kicks in right between the code taking the reference of the int and calling the operator. A simple workaround for that one is an intermediate step through a local variable:
int x;
ifile >> x;
dataPoint[i].X = x;
Which works because local variables are stable and are not subject to garbage collection.
None of this is a problem in native code. Do keep in mind that your ref class can easily call a native function. So separating the two can be useful and/or necessary.
You can't directly contain a native type within a managed type: this is just a restriction on C++/CLI. I'm thinking this might be to do with the possibilities of pointers within the native type. If the native type is directly within the managed type, then when managed objects get shuffled around during garbage collection, then these pointers would point to the original, now incorrect, memory.
Therefore the native object needs to be on the heap, so that its internals don't get changed by garbage collection. So you need to hold the vector as a pointer, and delete it appropriately. Note that the latter isn't entirely trivial, and you need to have some knowledge of C++/CLI (which differs subtly from C#). See http://msdn.microsoft.com/en-us/library/ms177197(v=vs.100).aspx.
Looking at the last time I did this, in my file I had
public:
!NetClass();
~NetClass() { this->!NetClass(); } // avoid arning C4461
private:
class NativeImpl* const m_pImpl; // can't contain NativeImpldirectly
And in the cpp file I had
NetClass::!NetClass()
{
// implement finalizer in ref class
delete m_pImpl;
}
You might just want to use the pimpl idiom here if you have more than one native class to contain. See Why should the "PIMPL" idiom be used?.
Finally, I last did this quite a while ago, and I'm just saying what worked for me at the time. If you're doing this, you really need to know what you're doing. I used a book called C++/CLI in Action, which I'd recommend.
Edit
This article on STL/CLR looks interesting: http://blogs.msdn.com/b/nikolad/archive/2006/06/16/stlclr-intro.aspx. To quote
STL/CLR, originally called STL.NET, is an implementation of Standard
Template Library (STL) that can operate with objects of managed types.
VC++ already has implementation of STL, however it is currently
working only with native types.
(I can't really help on your Q2)
I have a little trouble in understanding a wrapper class. It would be great if some one could help providing apt examples.
What is a C++ Wrapper Class and what are the circumstances of writing it ?
What is it's use any way ?
Thanks.
A "wrapper class" is a de facto term meaning a class that "wraps around" a resource; i.e, that manages the resource. When people write a wrapper, then, they are doing something like this:
class int_ptr_wrapper
{
public:
int_ptr_wrapper(int value = 0) :
mInt(new int(value))
{}
// note! needs copy-constructor and copy-assignment operator!
~int_ptr_wrapper()
{
delete mInt;
}
private:
int* mInt;
};
This class manages ("wraps") a pointer to an int. All resources should be wrapped in some fashion, for cleanliness (no explicit clean up code or noise) and correctness (destructor is guaranteed to run; cannot forget to clean up, and safe with exceptions).
This pattern is called Scoped-bound Resource Management (SBRM), though a far more common (but most esoteric) name is Resource-Acquisition is Initialization (RAII). The idea is to bind a resource's clean-up to a destructor, for the reasons given above: the scope handles the rest.
Note that I said it was missing a copy-constructor and copy-assignment operator. This is due to the Rule of Three. (See linked question for detailed explanation.) The simplest way to correctly implement this rule is with the copy-and-swap idiom, explained here.
Sometimes, it's not pragmatic to write wrapper class for resource clean-up, usually when the resource is unique or used once. (Or with transactional programming.) The solution to this is called scope guard, a way of writing clean-up code inside the function that needs it.
You may find more information by searching for it in your favorite search provider (that is, Google), or going to the "primary" document here. Note that Boost provides a utility for this, as it usually does for good idioms.
A wrapper is just some smallish class whose purpose is to provide a different interface than the thing it wraps. For example, it is common to take a C API and write one or more classes that "wrap" it to provide an object-oriented interface rather than a procedural one.
You asked for circumstances of writing wrapper classes.For example, if you are in a company that makes use of different types of cameras, let us say USB, firewire etc. Each of the manufacturers will provide a different set of functions through an API to start the camera, set the parameters and read the image stream from it.
Now the programmer who builds the applications in your company need to be insulated from all the specific details in the various APIs. Now, what you can do is write a wrapper class around the APIs for each of the cameras or smarter, just one class with simple functions, wrapping around the existing code provided by the API.
For instance, we can design classes
MyUSBCameraWrapperClass,
MyFirewireCameraWrapperClass
with some member functions like
setFrameRate(int fps),
getImgFrame(*framebuffer), etc.
The programmers in your company can then use MyUSBCameraWrapperClass usbcam; usbcam.setFrameRate(30), etc. You get the point??
A wrapper class is a class that wraps a functionality with another interface.
Suppose you have the function f():
void f() { std::cout << "hello\n"; }
A simple wrapper class might be
class C {
f() { std::cout << "hello\n"; }
};
You might write a wrapper when your existing codebase expects a particular interface. This is the essence of the adapter design pattern. Or you might wrap a function in a class if you wish to maintain state for that function. Or you might wrap a function in a class' constructor or destructor if you want it to conveniently and automatically be called for you in a correct and deterministic manner. And the list goes on.
I use two kinds:
resource wrappers for function pairs provided by the OS like
UNIXs: open/close, mmap/munmap, dlopen/dlclose
Windows: CreateFile/DestroyHandle, CreateFileMapping/CloseHandle, LoadLibrary/FreeLibrary
functional wrappers for functions provided by the OS like
UNIXs: write, read, dlsym
Windows: ReadFile, WriteFile, GetProcAddress
The resource wrapper makes certain, that compiler generated code worries about the destruction of the resource created by the constructor via what is today called RAII. It is easy to combine such classes via base/member class relationships into complex classes.
In case of the creation function fails, a system error exception is thrown, providing rich error information about the error.
The functional wrapper is used instead of the plain OS function. Also in case of failure a system exception is being thrown.
This way somebody using my code doesn't need a debugger and debug code to find out what is failing in a complex environment with many libraries and processes and remote machines.
Also these wrappers provide some OS abstraction -- the code using them does not have to worry about OS differences.