Mixing MFC and STL [closed] - c++

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Would you mix MFC with STL? Why?

Sure. Why not?
I use MFC as the presentation layer, even though the structures and classes in the back-end use STL.

Use STL whenever you can, use MFC when no alternative

I mix them all the time. The only minor PITA was serialization - the MFC containers (CArray, CList, CStringArray, etc.) support CArchive serialization, but when using STL containers you have to roll your own code. In the end I switched to using boost::serialization and dumped the MFC CArchive stuff.

Yes, I have mixed them before without problems. However, after using MFC for over a decade, I would never consider using it for a new project.

I use MFC for all my C++ projects, since none of my projects are console. MFC is elegant solution for Windows C++ developers. I hate QT, and I wont use WX on Windows. I dont care about portability, since my applications are only for Windows. I love MFC/ATL's CString class, std::string is very raw, doesn't have any "String" features in it. std::string is nothing more than vector<char>.
For all data storage and algorithms, I use STL. I do also use ConcRT PPL template classes, which are very much same as STL.

For collections in the data layer. I have no data to support this, but my suspicion is that the templated STL collections are more performant than their MFC counterparts.

Yes I do mix 'em because I find MFC too unwieldy for normal natural looking c++. Though you might have to write some code for conversions where your STL code talks to MFC code.

It was a very bad idea before Visual Studio 2003's (nearly) full support for the C++ Standard. Now it's not a bad idea at all. Whether it's a good idea depends on the context and what the skillset of your team is.

Yes, if both of the following conditions hold:
1) The language chosen for the project is C++ (which, of course, includes the STL - the S in the STL is for "Standard").
2) After a careful analysis, no better alternative is found or considered appropriate for the GUI support than MFC, and my development team goes for it.

It depends on what your definition of "mixing" is.
If you simply mean creating a project that uses both STL and MFC I don't see any harm in that at all. They serve a different purpose.

when mixing STL with other microsoft headers, be sure to define NOMINMAX,
otherwise your std::min function will be garbled into a syntax error because of the min(a,b) macro.

You should not use standard exceptions in an MFC application - your app might hang if you throw it inside a dialog. See this question for the reasons: Why does my MFC app hang when I throw an exception?

I had a struct with many simple type fields (UINT, CString, COLORREF, etc.). Project was compiling well.
Then I added a which I added a CArray to the struct. It wasn't compiling.
Then I implemented operator= and copy constructor for that struct (one using the other). It then compiled.
Some time after, doing maintenance to the struct I did an experiment: change the CArray to be a std::vector and remove the operator= and copy constructor. It compiled fine and the struct was being well-copied where operator= or copy constructor were being called.
The advantage is that I could dump a useless part of the code — prone to errors and probably not updated when someone did maintenance adding a field to the struct! — and I see that as a big advantage.
REASON:
Why I don't need the copy-constructor and the = assignment operator now?
Before, the struct had only simple type fields. So they were copiable. Being all of them copiable, makes the struct copiable. When I added the CArray field, this one was no copiable, because CArray derives from CObject, a class that explicilty makes these two functions private:
class AFX_NOVTABLE CObject
{
//...
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
//...
}
And CArray, being a class derived from CObject, doesn't do anything to override this behavior, so CArray will inherit it and rendering itself uncopiable. Having added a CArray before making my struct copiable, I was recieving the error:
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afxtempl.h(272) : error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afx.h(554) : see declaration of 'CObject::operator ='
c:\program files\microsoft visual studio 8\vc\atlmfc\include\afx.h(524) : see declaration of 'CObject'
This diagnostic occurred in the compiler generated function 'CArray<TYPE,ARG_TYPE> &CArray<TYPE,ARG_TYPE>::operator =(const CArray<TYPE,ARG_TYPE> &)'
with
[
TYPE=unsigned int,
ARG_TYPE=unsigned int &
]
The std::vector is copiable by its own definition:
// TEMPLATE CLASS vector
template<class _Ty,
class _Ax = allocator<_Ty> >
class vector
: public _Vector_val<_Ty, _Ax>
{ // varying size array of values
public:
typedef vector<_Ty, _Ax> _Myt;
Notice _Myt is a typedef to the vector class itself.
//...
vector(const _Myt& _Right)
: _Mybase(_Right._Alval)
{ // construct by copying _Right
if (_Buy(_Right.size()))
_TRY_BEGIN
this->_Mylast = _Ucopy(_Right.begin(), _Right.end(),
this->_Myfirst);
_CATCH_ALL
_Tidy();
_RERAISE;
_CATCH_END
}
//...
vector(_Myt&& _Right)
: _Mybase(_Right._Alval)
{ // construct by moving _Right
_Assign_rv(_STD forward<_Myt>(_Right));
}
_Myt& operator=(_Myt&& _Right)
{ // assign by moving _Right
_Assign_rv(_STD forward<_Myt>(_Right));
return (*this);
}
//...
}
So, adding a std::vector member field to a struct/class will not require you to implement copying functions inside it, only because of that new field.

I prefer to avoid STL and not to use it because it used to be not so standard when MFC was de-facto standard for about a decade. Also until recent versions of Visual C++ (and "standard" STL), MFC just have better performance.

Related

Old c++/objective-c++ project no longer complies code that stores UIKit objects in stl containers "Cast of a non-Objective-C pointer type ... UITouch"

So I built this engine designed to be cross platform. I have a TON of custom handling of multi-touch long past what UIKit does to aid in the game the engine is for.
To do this I introduced the design of a PlatformTouchManager (this c++ class has engine structs handling everything and turning it into plain old c structs in vectors.
Then for each platform there is a class that is a subclass an objective-c++ class iOSMultiTouch: public PlatformTouchManager { that will handle the UIKit objects and call and modify things on the superclass to keep its engine-level idea of multitouch state correct.
Now in this PlatformTouchManager (objective-c++) I have quite a bit of code that puts UIKit objective-c objects into STL containers such as
std::set<std::shared_ptr<UITouch*>> downSet;
std::vector<std::shared_ptr<UITouch*>> fingerList;
void iOSMultiTouch::touchesDown(NSSet* set) {
for (UITouch* t in set) {
std::shared_ptr<UITouch*> sptr = std::make_shared<UITouch*>(t);
if (downSet.find(sptr) == downSet.end()) {
downSet.insert(sptr);
}
}
}
I dont know whether this is a bad idea per say but it has worked for years of this project compiling.
Now all of a sudden I am getting this error /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/include/c++/v1/memory:2684:27: Cast of a non-Objective-C pointer type 'typename _CompressedPair::_Base2 *' (aka '__compressed_pair_elem<UITouch *__strong, 1> *') to 'UITouch *__strong *' is disallowed with ARC
And its blame goes down MANY stacks (into STL and out into my code) into this line std::shared_ptr<UITouch*> sptr = std::make_shared<UITouch*>(t);
Is there some sort of annotation I need to be putting in to help this code work and compile? Perhaps this is entirely a bad idea to do it this way?
I think the reason I did the class this way was that I thought I needed the class defined in objective-c++ code to be a c++ class to fit in and that that c++ class object in the header couldn't use objective-c things.
It is telling you that you have a pointer to __compressed_pair_elem which is not an Objective-C object, and cast it to a pointer to an Objective-C object, that is not allowed by ARC, it doesn't know how to treat the result.
The correct type for using in the C++ code is id:
std::set<std::shared_ptr<id __strong>> downSet;
std::vector<std::shared_ptr<id __strong>> fingerList;
void iOSMultiTouch::touchesDown(NSSet* set) {
for (UITouch* t in set) {
std::shared_ptr<id __strong> sptr = std::make_shared<id __strong>(t);
if (downSet.find(sptr) == downSet.end()) {
downSet.insert(sptr);
}
}
}
PS.Not sure if I am right, I do not have access to Xcode right now.
for (UITouch* t in set) may be incorrect and should be for (UITouch* t : set).
__strong may be odd in the declarations and may be omitted.

Why is Microsoft using struct rather than class in new code?

So normally I wouldn't ask a question like this because it seems like it could be opinion based or start some sort of verbal war on coding practices, but I think there might be a technical reason here that I don't understand.
I was looking over the code in the header files for vcpkg (a library packing manager that Microsoft is creating and is "new" code) because reading code generally is a good way to learn things you didn't know.
The first thing I noticed was the use of using rather than typedef.
Snippet from 'https://github.com/microsoft/vcpkg/blob/master/toolsrc/include/vcpkg/parse.h'
template<class P>
using ParseExpected = ExpectedT<std::unique_ptr<P>, std::unique_ptr<ParseControlErrorInfo>>;
I haven't personally used using this way before and an answer from: What is the difference between 'typedef' and 'using' in C++11?. Essentially, using is the new way to do it, and the benefit is that it can use templates. So Microsoft had a good reason to use using instead of typedef.
Looking at 'https://github.com/microsoft/vcpkg/blob/master/toolsrc/include/vcpkg/commands.h' I noticed that they did not use any classes. Instead it was only namespaces with a function or so in them. ie:
namespace vcpkg::Commands
{
namespace BuildExternal
{
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
}
}
I'm guessing that part of this is that the calling syntax looks essentially just like a static member function in a class, so the code performs the same but maybe saves some overhead by being a namespace instead of a class. (If anyone has any ideas on this too that would be great.)
Now the main point of all this. Why is Microsoft using structs instead of classes in their namespaces?
Snippet from 'https://github.com/microsoft/vcpkg/blob/master/toolsrc/include/vcpkg/parse.h':
namespace vcpkg::Parse
{
/* ... Code I'm excluding for brevity ... */
struct ParagraphParser
{
ParagraphParser(RawParagraph&& fields) : fields(std::move(fields)) {}
void required_field(const std::string& fieldname, std::string& out);
std::string optional_field(const std::string& fieldname) const;
std::unique_ptr<ParseControlErrorInfo> error_info(const std::string& name) const;
private:
RawParagraph&& fields;
std::vector<std::string> missing_fields;
};
}
Searching stackoverflow, I found an old question: Why Microsoft uses a struct for directX library instead of a class?
Which the answers were essentially, you don't have to declare things as public as default and a comment way at the bottom saying that it was old code.
If vcpkg was old code I would be completely satisfied, however, this is new code. Is it just some style they have that is a carry over (but using vs typedef isn't)? Or is it to save a line of code (public:)? Or is there some sort of overhead benefit? Or some other thing I haven't considered at all?
The only differences between struct and class are:
the default member access (public vs private) and
the default inheritance if you inherit from the type (public inheritance vs private inheritance).
The end result of 1 will be the same once the author has finished adding public:/private: to the type. 2 you can easily control yourself by being explicit when you inherit, rather than rely on the default. It's hardly a big deal and doesn't really matter.
As to why Microsoft uses struct rather than class in their code, you will have to ask some Microsoft people.
Regarding the free functions vs static functions, I don't think there is any overhead in this with classes (I haven't measured this at all, I would just think that most compiler would recognize that the class is basically just a namespace for the function). The thing is just: You don't need a class.
Using a class with only static functions is basically abusing the class as a namespace. So if you are only doing that, then be explicit about it and just use a namespace. Having a class there would only be confusing since you would think that maybe there could be some state here and just see that there is non when you see that the function in the class is static.
This is especially relevant if this is used a bit wrongly. Imagine someone instantiates a class A a with static member function f to call a.f(). It is no problem regarding performance, since the construction is a no-op and it will pretty much be equivalent to A::f(). But for the reader it seems like there is some kind of state involved and that is just confusing.
Regarding the other two: using is just superior to typedef throught being able to use templates and is (IMO) better readable. The struct vs class issue is just something over what has the better defaults, its not a big difference, but most often, what you want is what a struct does, so there is no reason to use a class.
To be (more) compatible with C
To avoid making everything public by using the public: keyword, since that all COM objects for example have only public member functions.

Creating a class in a DLL using std::string. C4251 warning

I would like to implement a simple class in a DLL, something like:
class MY_EXPORT_IMPORT MyClass
{
public:
//std::string anyPublicStr; //see point 3
protected:
std::string anyStr;
};
The problem is that Visual C++ compiler (2013 in this case) throws the following warning:
C:...MyClass.hpp:X: warning: C4251: 'MyClass::postfix' : class
'std::basic_string,std::allocator>'
needs to have dll-interface to be used by clients of struct 'MyClass'
I read several forums about why this warning is shown and how to solve it. But it is still not clear to me:
Most forums speak about exporting the templates, which make sense for templates, but std::string is already a specific type.
An other page said "Exporting std::string from a DLL is a VERY bad idea, for several reasons." Which make sense.
Others indicate as solution to encapsulate the parameter in a non-inline function. Well, in our case, the std::string is already protected, and switching to private does not solve the warning.
Personally I do not understand why this class could not just statically link the required STL libraries and make it to work without exporting anything. Or if the STL is dynamically linked, it should be also automatically linked in the dll.
Why is this Warning? How to solve it?
std::string is just a typedef:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
Regarding using STL on the dll interface boundary, generally it is simpler if you avoid that and I personally prefer it if possible. But the compiler is just giving you a warning and it doesn't mean that you will end in a problem. Have a look at: DLLs and STLs and static data (oh my!)

STL vector used in managed code

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)

Implications of using std::vector in a dll exported function

I have two dll-exported classes A and B. A's declaration contains a function which uses a std::vector in its signature like:
class EXPORT A{
// ...
std::vector<B> myFunction(std::vector<B> const &input);
};
(EXPORT is the usual macro to put in place _declspec(dllexport)/_declspec(dllimport) accordingly.)
Reading about the issues related to using STL classes in a DLL interface, I gather in summary:
Using std::vector in a DLL interface would require all the clients of that DLL to be compiled with the same version of the same compiler because STL containers are not binary compatible. Even worse, depending on the use of that DLL by clients conjointly with other DLLs, the ''instable'' DLL API can break these client applications when system updates are installed (e.g. Microsoft KB packages) (really?).
Despite the above, if required, std::vector can be used in a DLL API by exporting std::vector<B> like:
template class EXPORT std::allocator<B>;
template class EXPORT std::vector<B>;
though, this is usually mentioned in the context when one wants to use std::vector as a member of A (http://support.microsoft.com/kb/168958).
The following Microsoft Support Article discusses how to access std::vector objects created in a DLL through a pointer or reference from within the executable (http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q172396). The above solution to use template class EXPORT ... seems to be applicable too. However, the drawback summarized under the first bullet point seems to remain.
To completely get rid of the problem, one would need to wrap std::vector and change the signature of myFunction, PIMPL etc..
My questions are:
Is the above summary correct, or do I miss here something essential?
Why does compilation of my class 'A' not generate warning C4251 (class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of...)? I have no compiler warnings turned off and I don't get any warning on using std::vector in myFunction in exported class A (with VS2005).
What needs to be done to correctly export myFunction in A? Is it viable to just export std::vector<B> and B's allocator?
What are the implications of returning std::vector by-value? Assuming a client executable which has been compiled with a different compiler(-version). Does trouble persist when returning by-value where the vector is copied? I guess yes. Similarly for passing std::vector as a constant reference: could access to std::vector<B> (which might was constructed by an executable compiled with a different compiler(-version)) lead to trouble within myFunction? I guess yes again..
Is the last bullet point listed above really the only clean solution?
Many thanks in advance for your feedback.
Unfortunately, your list is very much spot-on. The root cause of this is that DLL-to-DLL or DLL-to-EXE is defined on the level of the operating system, while the the interface between functions is defined on the level of a compiler. In a way, your task is similar (although somewhat easier) to that of client-server interaction, when the client and the server lack binary compatibility.
The compiler maps what it can to the way the DLL importing and exporting is done in a particular operating system. Since language specifications give compilers a lot of liberty when it comes to binary layout of user-defined types and sometimes even built-in types (recall that the exact size of int is compiler-dependent, as long as minimal sizing requirements are met), importing and exporting from DLLs needs to be done manually to achieve binary-level compatibility.
When you use the same version of the same compiler, this last issue above does not create a problem. However, as soon as a different compiler enters the picture, all bets are off: you need to go back to the plainly-typed interfaces, and introduce wrappers to maintain nice-looking interfaces inside your code.
I've been having the same problem and discovered a neat solution to it.
Instead of passing std:vector, you can pass a QVector from the Qt library.
The problems you quote are then handled inside the Qt library and you do not need to deal with it at all.
Of course, the cost is having to use the library and accept its slightly worse performance.
In terms of the amount of coding and debugging time it saves you, this solution is well worth it.