Archive for the ‘C++’ Category.

Переключение между H и CPP файлами в Visual Studio 7/7.1/8/9

Мне достаточно часто необходимо переключаться между H и CPP файлами в процессе разработки. На работе обычно у меня стоит Visual Assist X, для которого это одна из многих опций. Но вот понадобилось сделать тоже самое, но без Visual Assist X, борьба за использование только лицензионного ПО. В 2005 студии есть набор макросов,один из которых умеет переключаться между H и CPP, а вот в 2003 не нашел. Поискал в интернете и нашел этот макрос.

 
    Sub GetFriendFile()
        'DESCRIPTION: Opens the corresponding .h / .cpp file
        Dim currentFileName As String
        Dim newFileName As String
        currentFileName = Application.ActiveDocument.FullName
        newFileName = ""
 
        If (UCase(Right(currentFileName, 2)) = ".H") Then
            newFileName = Left(currentFileName, Len(currentFileName) - 2) + ".CPP"
        ElseIf (UCase(Right(currentFileName, 4)) = ".CPP") Then
            newFileName = Left(currentFileName, Len(currentFileName) - 4) + ".H"
        End If
 
        If newFileName <> "" Then Application.Documents.Open(newFileName)
 
    End Sub
 

Для того чтобы его использовать идете в Tools | Macros | Macros IDE появится новое окно в котором будет открыт MyMacros проект. Добавьте новый модуль, назовите его скажем Switch2cpp. И далее вставьте в него функцию GetFriendFile, сохраните и затем назначьте сочетание клавиш.

Для этого выберите Tools|Options|Environment|Keyboard и там выберите из лист бокса Macros.MyMacros.Switch2cpp.GetFriendFile и сочетание клавиш, которые будут выполнять данный макрос, после этого не забудьте нажать кнопку Assign - наслаждайтесь.

Материал испльзуемый при написании поста:

По воле рока, так случилось, иль MFC CMap vs STL std::map и stdext::hash_map

На работе в проекте используется MFC, причем везде и много. При запуске иногда программа серьйозно притормаживает. Натравить профайлер не могу, BoundChecker просто загнулся, а остальные я не пробовал, т.к руководству это не нужно и, соответственно, времени отпрофайлить мне никто не даст. Так вот, найдя проблемный участок кода, я обнаружил, что там происходит вставка элементов в CMap (класс MFC реализованный с помощью хеш-массива ) , причем при увеличении кол-ва элементов, время на вставку возростало. Попрошу извинить меня за предложения типа "при увеличении кол-ва элементов, время на вставку возростало" , из отсутствия профайлера я более точно сказать не могу, в проекте все замерял на глаз. Но эти наблюдения сподвигли меня написать маленький тест по сравнению производительности STL и MFC.

Тест достаточно простой - вставка элементов в CMap, std::map и stdext::hash_map. С помощью кода ниже я нагенерировал неповторяющиеся последовательноси символов

 
void GenerateSequence(const std::string& file_name,int nNumCh)
{
	if(nNumCh&gt;16)
		return;
 	char buf[]="0123456789abcdefg";
	std::string sRealStr(buf,buf+nNumCh);
 	int nCount=0;
	std::ofstream f(file_name.c_str(),std::ios::out|std::ios::trunc);
 
	while(std::next_permutation(sRealStr.begin(),sRealStr.end()))
 	{
 		++nCount;
 		f<<" "<<sRealStr;
 		if(!(nCount%15))
 			f<<std::endl;
	}
}
 

тестировал на последовательностях из 6,7,8 и 9 символов, соответственно 720, 5040, 40320 и 362880 элементов. Результаты приведены ниже в виде таблицы и диаграммы, время в секундах


STL map MFC map Initialized MFC map STL hashmap
719 0.0006866790 0.0004520130 0.0003318860 0.0004151370
5039 0.00598372 0.00580493 0.00249222 0.00312610
40319 0.07176890 0.69810400 0.02297470 0.02608380
362879 0.77434000 241.62900000 0.24009400 11.61740000

Results

Пару слов о легенде, думаю не совсем понятно, что такое Initialized MFC map - это перед использованием CMap контейнер инициализируется количеством элементов которые в него вставят.После этого теста многое стало на свои места - мы используем тот случай, который имеет самый высокий столбец на графике. Вот так вот ...

boost::serialization - бинарная сериализация

Довольно часто приходться сериализовать\десериализовать объекты например при передачи их по сети. Вместо того, чтобы передавать MessageID и потом, расспознав его, принимать остальную часть сообщения, можно использовать библиотеку которая будет выполнять эту работу сама. Одной из библиотек котороя обладает вышеописанной функциональностью является boost::serialization По ссылке находится вполне исчерпывающая документация, но я столкнулся со сложностью и внятного ответа в документации не нашел. Проблема была в следующем, хотелось бы иметь возможность передавать по сети объекты наследованные от какого-нибудь базового класса и затем десериализовать их через указатель на базовый класс. Например:

 
class Base
{
};
 
class Derived:public Base
{
  int nValue;
};
 
//....
 
void save()
{
  Base* pDerived = new Derived;
  binarystream_out << pDerived;
};
 
void load()
{
  Base* pDerived = 0;
  binarystream_in >> pDerived;
};
 

Проблема заключается в том, что при десериализации член nValue класса Derived не будет корректно десериализован, он будет содержать какой-то мусор. В примерах к библиотеке эта проблема решается оригинальным способом, первый раз десериализовать объект явно указав его тип.

 
void load()
{
  Derived* pDerived ;
  binarystream_in >> pDerived;
  //после этого класс регистрируется  и ниже в коде можна вызывать
  Base* pDerived2;
  binarystream_in >> pDerived2;
  //десериализация проходит корректно
};
 

Наверное нелишним будет упомянуть, что я столкнулся с этой же ситуацией в MFC и долго просидел в дебагере пока понял что не так.

Проблема решается достаточно просто, достаточно зарегистрировать класс в input stream.

 
void load()
{
  Base* pDerived ;
  binarystream_in.register_type(static_cast<Derived*>(0));
  binarystream_in >> pDerived;
};
 

boost::serialization example