Alf said:
* Larry I Smith:
Uhm ... extraordinary claims require extraordinary proofs... ;-)
Do you have some (preferentially small) example code the readers of this
thread could discuss & time?
By force of habit I used an approach specified by my company's
Design Standards doc. Now you want me to prove that our
Corporate Engineering Council is correct in their design decisions.
As they say, "I just work here". The design standards to which we
must conform were written by folks far smarter than I to ensure
platform portability (win98/2k/xp; various versions of HP/UX, SunOS,
Solaris, Linux, etc, etc, etc). Those design standards forbid,
or restrict, our use of many common C++ features because they may
have problems (portability or performance) on one or more of the
supported platforms. Those who work here have no control over
these design standards, so further discussion on it is pointless.
As I stated in my earlier post, I'll make an effort in the
future to not impose those design limitations on code
snips I post here.
As far as the original OP's question (how to get the data from
a std::string into a seperate byte array), I put together a test
program (see below) which compares several approaches. Results
of running the program on WinXP and Linux are in the comments
at the top of the program. I know the code could be greatly
improved (better error handling, etc), but I've already spent
way too much time on this issue.
On Windows all but one of the vector approaches are 5 to 15
times slower than the new/memcpy approach. (I begin to see
why the Design Doc mandates the new/memcpy approach...)
On Linux the vector approaches are comparable to the new/memcpy
approach.
Excluding the new/memcpy approach, it seems that the following
approach using std::string.c_str() is the most portable
(i.e. matches the new/memcpy approach); although it does depend
on strict left-to-right argument evaluation - which I'm not
allowed to use, but others may be.
// 'str' is a std::string containing the input data.
const char * data;
vector<char> vec(data = str.c_str(), data + str.length());
Regards,
Larry
// vtest.cpp - test vector creation vs new/memcpy.
// 1) tests with std::string iterators as the input data
// 2) tests with std::string.c_str() as the input data
// 3) tests with a char buffer as the input data source.
// to compile:
// Windows: cl /EHsc vtest.cpp
// Linux: g++ -o vtest vtest.cpp
/*
* Sample output using MSVC v7 on WinXP,
* on a P4 2GHZ with 512MB RAM:
* Input test data size bytes is: 10485760
* Test creating a vector from std::string iterators:
* 0.046 seconds - (1x) new,memcpy()
* 0.655 seconds - (14x) vector(first,last)
* 0.686 seconds - (15x) vector(sz),copy()
* 0.608 seconds - (13x) vector(),reserve(sz),copy()
* Test creating a vector from std::string.c_str():
* 0.047 seconds - (1x) new,memcpy()
* 0.046 seconds - (1x) vector(first,last)
* 0.343 seconds - (7x) vector(sz),copy()
* 0.249 seconds - (5x) vector(),reserve(sz),copy()
* Test creating a vector from a char buffer:
* 0.047 seconds - (1x) new,memcpy()
* 0.047 seconds - (1x) vector(first,last)
* 0.343 seconds - (7x) vector(sz),copy()
* 0.249 seconds - (5x) vector(),reserve(sz),copy()
*
* Sample output using g++ v3.3.5 on SuSE Linux 9.3,
* on a P2 450MHZ with 384MB RAM:
* Input test data size bytes is: 10485760
* Test creating a vector from std::string iterators:
* 0.15 seconds - (1x) new,memcpy()
* 0.17 seconds - (1x) vector(first,last)
* 0.17 seconds - (1x) vector(sz),copy()
* 0.15 seconds - (1x) vector(),reserve(sz),copy()
* Test creating a vector from std::string.c_str():
* 0.15 seconds - (1x) new,memcpy()
* 0.15 seconds - (1x) vector(first,last)
* 0.17 seconds - (1x) vector(sz),copy()
* 0.16 seconds - (1x) vector(),reserve(sz),copy()
* Test creating a vector from a char buffer:
* 0.1 seconds - (1x) new,memcpy()
* 0.15 seconds - (1x) vector(first,last)
* 0.21 seconds - (2x) vector(sz),copy()
* 0.15 seconds - (1x) vector(),reserve(sz),copy()
*/
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
// print the elapsed time in seconds
double elapsed(const string& txt, clock_t start, clock_t end,
double orig)
{
double et = static_cast<double>(end - start) / CLOCKS_PER_SEC;
cout << " "
<< et
<< " seconds - ";
if (orig > 0.0)
{
cout << " ("
<< static_cast<int>(et/orig + 0.5) << "x)";
}
else
{
cout << " (1x)";
}
cout << " " << txt << endl;
return et;
}
template <class InIt>
void testvec(string::size_type sz, const char * data,
InIt first, InIt last)
{
clock_t start, end;
double orig = 0.0;
// ------------------------------------
// time using new/memcpy to create a char buffer
// copy of the test data
{
char *buf = 0;
start = clock();
// allocate the memory for buf[].
// for this simple program, we just terminate if
// any exception is thrown.
try
{
buf = new char[sz];
}
catch(...)
{
cout << "buf = new[] failed" << endl;
return;
}
memcpy(buf, data, sz);
end = clock();
orig = elapsed("new,memcpy()", start, end, orig);
delete[] buf;
}
// ------------------------------------
// time creating a vector from the test data using
// the vector's constructor
{
start = clock();
vector<char> vec1(first, last);
end = clock();
elapsed("vector(first,last)" ,start, end, orig);
}
// ------------------------------------
// time creating a vector from the test data using a
// pre-sized vector and copy()
{
start = clock();
vector<char> vec2(sz);
copy(first, last, vec2.begin());
end = clock();
elapsed("vector(sz),copy()", start, end, orig);
}
// ------------------------------------
// time creating a vector from the test data using
// vector.reserve() and copy()
{
start = clock();
vector<char> vec3;
vec3.reserve(sz);
copy(first, last, vec3.begin());
end = clock();
elapsed("vector(),reserve(sz),copy()", start, end, orig);
}
return;
}
int main()
{
// we'll use 10MB as the test data size
string::size_type sz = (1024 * 1024 * 10);
cout << "Input test data size bytes is: " << sz << endl;
// test vector using string iterators to access the input data
{
cout << "Test creating a vector from"
<< " std::string iterators:" <<endl;
// make a test string holding 'sz' blanks
string str(sz, ' ');
testvec(sz, str.c_str(), str.begin(), str.end());
}
// test vector using string.c_str() as input data
{
cout << "Test creating a vector from"
<< " std::string.c_str():" <<endl;
const char * data;
// make a test string holding 'sz' blanks
string str(sz, ' ');
// WARNING: this assumes that left-to-right
// argument evaluation is guaranteed
// by the compiler.
testvec(sz, data = str.c_str(), data, data + sz);
}
// test vector using a char buffer as input data
{
cout << "Test creating a vector from a"
<< " char buffer:" <<endl;
try
{
// make a char buffer holding 'sz' blanks
char * data = new char[sz];
memset(data, ' ', sz);
testvec(sz, data, data, data + sz);
delete[] data;
}
catch(...)
{
cout << "data = new[] failed" << endl;
}
}
return 0;
}