You could also have combined construction and assignment, though I doubt that would have made any noticeable difference.
Code:std::vector<CString> v( &g_strings[0], &g_strings[ size ] );
Printable View
You could also have combined construction and assignment, though I doubt that would have made any noticeable difference.
Code:std::vector<CString> v( &g_strings[0], &g_strings[ size ] );
It's amazing how so many people keep failing to answer the question.
The original poster asked which containers were faster, and which were better. He didn't ask for people to go off on a ideological trip about standards.
I'll only address the speed question. In my tests, STL containers are not always particularly fast. In many cases, the MFC containers are faster, sometimes dramatically so. If speed is your concern (and it's sometimes an absolutely fundamental issue), I would tend to favour the MFC containers, but it's better to evaluate on a case-by-case basis. My advice: do a comparative test with both with the kind of data your app will use.
A hopelessly slow application in 100% standard C++ is no use to anybody.
Can you post your tests ?? It has been shown on Codeguru and other locations
the std::vector is as fast or faster than CArray. (I hope you were not testing
Debug version or with iterator checking).
Isn't discussion of "better" include discussion of standards?
Let's see your tests against optimized code, with the proper preprocessor flags used in creating the program (_SECURE_SCL=0 is the one that people often missed if you use Visual Studio).Quote:
I'll only address the speed question. In my tests, STL containers are not always particularly fast. In many cases, the MFC containers are faster, sometimes dramatically so.
Show your tests. Compiler, version, whether it is optimized properly, etc.Quote:
A hopelessly slow application in 100% standard C++ is no use to anybody.
Regards,
Paul McKenzie
Paul, have you ever tried the "sorting project" posted here with and without _SECURE_SCL=0 or we are just talking using "holy scripts"?
Regards,
Ovidiu
The _SECURE_SCL=0 turns off iterator checking in release mode. With iterator checking on, the code will show degradation. It seems your original project did not have this set in release mode. Rerun your tests, but set this flag.
The issue is that Visual Studio doesn't have this set to 0 when building a release version, thereby the STL applications were slower than they should be if you were not aware of this flag. This has been reported to MS as to the flaw, and some haven't had too many nice words to say to the VS engineers about it.
Secondly, I think I mentioned that STL is not just containers -- you have the algorithm functions. MFC doesn't have these functions, so the advice "never to use STL in an MFC application" needs to be clarified.
Regards,
Paul McKenzie
I knew that.
Ok, seems to be logical and good to add "no additional run-time checking, means more speed" in Programmer's Holy Book.
However, until seeing somethig is really real, I'm Thomas The Unbeliever Programmer so I said: "Let's try it!".
I was expecting a significant speed increasing by disabling run-time iterators checking (setting _SECURE_SCL=0), but... surprise: the result was quite the same.
Or course, would be stupid to generalize and take that as a generally true statement.
In other non-trivial cases, the result may be as "canonically" expected.
Maybe I was wrong, then you can try it. That program is not tabu and doesn't bite. :).
I said:
Is it absolutelly necessary to show "if it's not absolutelly necessary" phrase by using big bright letters and having Las Vegas effects? :D
Well, I developed MFC applications for years and, generally, there were rare cases of "absolutelly necessary".
One beside note.
Run-time ckecking is not evil. In many cases, a little bit smaller speed performance is preferable to other nasty problems.
As an example, once I found something like this:
This is just a trivial example. May be others, having more insidious sources of painful run-time headaches.Code:v.erase(iter);
//...
--iter;
We believe or not, this is the real mortals' world, below the clouds. ;)
That's right. A lightning fast application in 100% standard C++ is much better.
There's nothing inherently slow with the C++ standard libraries. And from what I know the Microsoft implementation is licenced from Dinkumware, a high quality provider. They wouldn't get away with a crappy implementation. And if Microsoft implemented it themselves I don't think they would have anything to gain from making their C++ standard libraries inferior on purpose to promote the MFC?
I've heard claims like this over and over again in forums and each time when the benchmarks are finally posted the only thing they prove conclusively is that the poster doesn't know what he's doing.Quote:
In my tests, STL containers are not always particularly fast. In many cases, the MFC containers are faster, sometimes dramatically so.
Indeed, somethng like
...is much better than the equivalent "non-standard" MFC implementation. :)Code:#include <iostream>
int main()
{
std::cout << "Hello world!" << std::endl;
return 0;
}
However, if you want to do more, like showing something user friendly, print something, let user push something and so on, the "100% standard C++" doesn't help you so much. :p
Yeah, I know... The Microsoft's Mondial Conspiracy... Kelly, the Al Bundy's blonde daughter, has told me about it... :rolleyes:
"Life on Venus is much more comfortable than life on Mercury"
Is that true? I think, you can just presume but don't exactly know until make a try. ;)
actually, your code gives an unfair comparison; in the line
you are treating a CString as a POD of the same size and content of a TCHAR*, so basically, you are sorting an array of char pointers; whereas in the lineCode:qsort(arr.GetData(), size, sizeof(CString*), CompareStrings);
you are sorting a vector of CString objects, which is obviously slower; the two happens to give the same results only because you are using a Microsoft compiler.Code:std::sort( v.begin(), v.end() );
Now, in order to make a fair comparison, you should pass the CString's to std::sort as a sequence of pod objects, as in the following adaptation of your code sample:
the lineCode:#include "stdafx.h"
#include "array.h"
#include <boost/iterator/transform_iterator.hpp>
namespace details
{
template< class T, class PodT >
struct AsPod: std::unary_function<T&,PodT&>
{
BOOST_STATIC_ASSERT( sizeof(T) == sizeof(PodT) );
PodT& operator()( T& v ) const {
return *(PodT*)(&v);
}
};
}
template< class PodT, class Iter >
boost::transform_iterator< details::AsPod<typename Iter::value_type, PodT>, Iter >
make_pod_iterator( Iter it )
{
return boost::make_transform_iterator( it, details::AsPod<typename Iter::value_type, PodT>() );
}
struct CompareStrings
{
bool operator()( TCHAR* left, TCHAR* right)
{
return ((CString&)left).Compare((CString&)right) < 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
ShowWindow(::GetConsoleWindow(), SW_HIDE);
const size_t size = GetArraySize();
LARGE_INTEGER begin, end, freq;
::QueryPerformanceFrequency(&freq);
::QueryPerformanceCounter(&begin);
std::vector<CString> v;
v.resize(size);
for(size_t index = 0; index < size; index++)
{
v[index] = g_strings[index];
}
::QueryPerformanceCounter(&end);
double fill = ((double)end.QuadPart - begin.QuadPart) * 1000.0 / freq.QuadPart;
::QueryPerformanceCounter(&begin);
std::sort( make_pod_iterator<TCHAR*>( v.begin() ), make_pod_iterator<TCHAR*>( v.end() ), CompareStrings() );
::QueryPerformanceCounter(&end);
double sort = ((double)end.QuadPart - begin.QuadPart) * 1000.0 / freq.QuadPart;
CString strResult;
strResult.Format(_T("Array size: %u")
_T("\nFill time: %lf ms.")
_T("\nSort time: %lf ms.\n"),
size, fill, sort);
::MessageBox(NULL, strResult, _T("STL WAY"), MB_OK);
return 0;
}
gives the true semantically equivalent version of the lineCode:std::sort( make_pod_iterator<TCHAR*>( v.begin() ), make_pod_iterator<TCHAR*>( v.end() ), CompareStrings() );
and my results for sorting ( with _SECURE_SCL = 0, array size = 59956 ( I doubled the original array to make it to take longer ) ) areCode:qsort(arr.GetData(), size, sizeof(CString*), CompareStrings);
MFC: ~35 ms
STL: ~18 ms
( PS: I quickly tested the code above, hope there's no error :) )
moreover, note that not only the STL version seems faster, my pod_iterator also supports checked vector iterators in debug builds ...
EDIT: I just want to precise that both the qsort and pod_iterator versions are acceptable because we suppose that CString can be treated as a POD in VC++. BTW, note that the STL version makes also much more clear that we are doing something out-of-standard ...
EDIT 2: of course, if you don't like all the make_pod_iterator template stuff and you don't care of having a consistent iterator interface, you can simply write
instead of "std::sort( make_pod_iterator ..."; but IMHO, this is less clear and dangerous; moreover the speed seems the same ...Code:std::sort( (TCHAR**)&v[0], (TCHAR**)&v[ v.size() - 1 ], CompareStrings() );
actually, I wrote the TCHAR** version quickly and there is an error: it ignores the last CString; you should change "(TCHAR**)&v[ v.size() - 1 ]" to "((TCHAR**)&v[0]) + v.size()" to get the correct code. Anyway, as I said above, I like more the make_pod_iterator version which has the same speed of the TCHAR** code and offer more safety for free ( ... and it's more C++-esque ! :) ).
Using std::string instead of CString with the VS2010 compiler can produce faster results without needing to rely on tricks (treating the CString as a POD).
The std::string object in VS2010 supports the move constructors, while the CString object doesn't (at least as far as I can tell).
This results in sort() being able to perform better on a vector<std::string> than on a vector<CString>, assuming no POD tricks.
My system (using modified versions of the previously posted code) produced the following results:
qsort on vector<CString>: 41.18 ms
sort on vector<CString> with function comparator: 138.9 ms
sort on vector<CString> with functor comparator: 129.2 ms
sort on vector<std::string> with function comparator: 43.6 ms
sort on vector<std::string> with functor comparator: 35.5 ms
For the qsort, I simply duplicated the original test. I don't really consider this test valid as it does treat the CString as a POD, but I wanted to include it as a comparison.
For the other tests, std::sort is used with either a function comparator or a functor comparator. There are no POD tricks being done - the comparator simply compares the 2 strings. Since std::string supports move constructors in VS2010, this results in better performance than the vector with CString.