Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, <Аноним>, Вы писали:
А>>Дело не в промежуточном буфере и не в перераспределении памяти,
А>>дело в том что методы "copy" или "insert" производят посимвольное копирование,
А>>вот это и является не оптимальным.
AD>В случае с std::string выбирать не приходиться. Это тебе не std::vector<char>.
А>>посмотри ссылку на которую указал Odi$$ey http://www.rsdn.ru/Forum/Message.aspx?mid=361479.
AD>Там как раз речь идёт о std::vector<char>
Выбор всегда есть, в этом и заключается прелесть программирования!
(Предыдущие сообщения написаны мной, я решил зарегистрироваться)
В сообщении на которое указал Odi$$ey, надо было обратить внимание на время выполнения тестов,
они ясно показывают что использование методов "copy" или "insert" является не оптимальным вариантом.
Я написал свой тест, он показывает что ситуация с string аналогичная vector<char>.
В своем тесте я написал несколько вариантов загрузки файла в строку.
null — пустышка, открывает файл и вычислет его размер (для чистоты эксперимента);
system — использует функции Window для работы с файлом;
system shared buffer — то же что и system, только использует общий буфер;
остальные функции работают с файлом через stl:
buffer — считывает сторку через буфер;
string.resize — использует прямую запись в данные string (опасный вариант!);
string.insert и std::copy — это ваш вариант.
Результаты теста:
test file "D:/temp/test/test1.txt", size 320, count 100000
null — 2023 ms
system — 2053 ms
system shared buffer — 2043 ms
buffer — 5367 ms
string.resize — 4637 ms
string.insert — 5568 ms
std::copy — 5238 ms
test file "D:/temp/test/test2.txt", size 19047, count 10000
null — 200 ms
system — 1031 ms
system shared buffer — 1032 ms
buffer — 3084 ms
string.resize — 3145 ms
string.insert — 10004 ms
std::copy — 8292 ms
test file "D:/temp/test/test3.txt", size 750330, count 1000
null — 20 ms
system — 10595 ms
system shared buffer — 9885 ms
buffer — 15252 ms
string.resize — 14440 ms
string.insert — 40589 ms
std::copy — 33868 ms
Программа собрана на C++Builder 6, с включенной оптимизацией.
Текст программы:
#include <string>
#include <fstream>
#include <algorithm>
#include <streambuf>
#include <iostream>
#include <windows.h>
class t_buffer
{
public:
void* data;
int size;
inline t_buffer( int s = 0 ) { size = s; data = (s > 0) ? malloc(s) : 0; }
inline ~t_buffer() { size = 0; if (data) { free(data); data = 0; } }
inline void grow( int s ) { if (size < s) data = realloc(data, size = s); }
};
using namespace std;
int file_size( const string& filename )
{
ifstream file( filename.c_str(), ios::in | ios::binary );
file.seekg(0, ios_base::end);
return file.tellg();
}
//------------------------------------------------------------------------------
string read_str_NULL( const string& filename )
{
string result;
ifstream file( filename.c_str(), ios::in | ios::binary );
size_t filesize;
file.seekg(0, ios_base::end);
filesize = file.tellg();
if (filesize == 0) return result;
file.seekg(0, ios_base::beg);
return result;
}
string read_str_SYSTEM( const string& filename )
{
HANDLE fh;
string result;
DWORD filesize;
fh = ::CreateFile( filename.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0 );
if (fh == INVALID_HANDLE_VALUE) return result;
filesize = ::GetFileSize(fh, 0);
if (filesize > 0)
{
DWORD readsize = 0;
t_buffer buffer(filesize);
if ( ::ReadFile(fh, buffer.data, filesize, &readsize, 0) != 0 )
result = string((char*)buffer.data, readsize);
}
::CloseHandle(fh);
return result;
}
string read_str_SYSTEM_SHARED_BUFFER( const string& filename )
{
static t_buffer buffer;
HANDLE fh;
string result;
DWORD filesize;
fh = ::CreateFile( filename.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0 );
if (fh == INVALID_HANDLE_VALUE) return result;
filesize = ::GetFileSize(fh, 0);
if (filesize > 0)
{
DWORD readsize = 0;
buffer.grow(filesize);
if ( ::ReadFile(fh, buffer.data, filesize, &readsize, 0) != 0 )
result = string((char*)buffer.data, readsize);
}
::CloseHandle(fh);
return result;
}
string read_str_BUFFER( const string& filename )
{
ifstream file( filename.c_str(), ios::in | ios::binary );
size_t filesize;
file.seekg(0, ios_base::end);
filesize = file.tellg();
if (filesize == 0) return string();
file.seekg(0, ios_base::beg);
t_buffer buffer(filesize);
file.read((char*)buffer.data, filesize);
string result((char*)buffer.data, filesize);
return result;
}
string read_str_RESIZE( const string& filename )
{
string result;
ifstream file( filename.c_str(), ios::in | ios::binary );
size_t filesize;
file.seekg(0, ios_base::end);
filesize = file.tellg();
if (filesize == 0) return result;
file.seekg(0, ios_base::beg);
result.resize(filesize);
file.read( (char*)result.data(), filesize );
return result;
}
string read_str_INSERT( const string& filename )
{
string text;
ifstream file;
size_t filesize;
file.open( filename.c_str(), ios::in | ios::binary );
file.seekg(0, ios_base::end);
filesize = file.tellg();
file.seekg(0, ios_base::beg);
text.reserve(filesize);
text.insert( text.begin(), istreambuf_iterator<char>(file), istreambuf_iterator<char>() );
return text;
}
string read_str_COPY( const string& filename )
{
string text;
ifstream file;
size_t filesize;
file.open( filename.c_str(), ios::in | ios::binary );
file.seekg(0, ios_base::end);
filesize = file.tellg();
file.seekg(0, ios_base::beg);
text.reserve(filesize);
copy( istreambuf_iterator<char>(file),
istreambuf_iterator<char>(), std::back_inserter(text) );
return text;
}
//------------------------------------------------------------------------------
typedef string (*t_read_method)( const string& );
struct t_method_item
{
const char* name;
t_read_method method;
};
static const t_method_item c_methods[] =
{
{ "null", read_str_NULL },
{ "system", read_str_SYSTEM },
{ "system shared buffer", read_str_SYSTEM_SHARED_BUFFER },
{ "buffer", read_str_BUFFER },
{ "string.resize", read_str_RESIZE },
{ "string.insert", read_str_INSERT },
{ "std::copy", read_str_COPY },
{ 0, 0 }
};
void test_methods( int count, const string& filename )
{
const t_method_item* i;
int c;
unsigned int time;
std::cout << std::endl << "test file \"" << filename << "\", size " << file_size(filename) << ", count " << count << std::endl;
for ( i = c_methods; i->name; i++ )
{
time = ::GetTickCount();
for ( c = count; c > 0; c-- )
i->method(filename);
time = ::GetTickCount() - time;
std::cout << i->name << " - " << time << " ms" << std::endl;
}
}
void main()
{
char t;
test_methods(100000, "D:/temp/test/test1.txt"); // 320 b
test_methods( 10000, "D:/temp/test/test2.txt"); // 18,6 Kb
test_methods( 1000, "D:/temp/test/test3.txt"); // 732 Kb
std::cin >> t;
}