ICQ - форум. Всё про ICQ.  

Вернуться   ICQ - форум. Всё про ICQ. > Мастерская > Программирование

Программирование C / C++ / Visual C++ / Delphi / Visual Basic / ASM / Windows / Pascal

 
 
Опции темы Оценить тему
Старый 08.01.2010, 19:39   #1
Почти участник
 
Регистрация: 02.02.2008
Сообщений: 1,843

Репутация: 5599
По умолчанию Советы по C/C++

Предлагаю выкладывать в этой теме советы по программированию на C/C++
Для других языков можно создать отдельные темы, закреплю

============================== =========================

  • Передача параметров в функцию по константной ссылке
    Предположим, что нам нужно передать в функцию некоторый объект, размер которого больше, чем размер указателя в целевой системе (больше 4 байт на х86 или 8 байт на х64)

    Это - наиболее неоптимальный и часто используемый метод
    PHP код:
    void function(QString sString)
    {
      
    // какие-то действия

    В данном случае в функцию будет копироваться весь объект, что существенно сказывается на производительности

    Если предполагается, что параметр не будет изменяться в функции, то можно передать его как константу
    PHP код:
    void function(const QString sString)
    {
       
    // какие-то действия

    А если будем использовать такую модификацию функции, то в функцию будет передаваться указатель на объект, который мы изменить в функции не сможем. Это - наиболее оптимальный и безопасный метод
    PHP код:
    void function(const QString &sString)
    {
       
    // какие-то действия

    В таком случае мы передаем 4 или 8 байт как параметр, и, если параметров не больше двух, то наиболее оптимальным будет объявление функции как fastcall. При использовании этого соглашения параметры в функцию передаются через регистры (только если эти параметры не больше регистров, т.е. не больше 4 байт на х86 или 8 байт на х64)
    Заметьте, что тип int и меньше (либо long long на x64) (short, char или bool например) не имеет смысла передавать по константной ссылке. В случае с типами, размер которых меньше размера указателя, мы только потеряем объем памяти == sizeof(*void) - sizeof(тип)

  • Оператор +-
    Помнится, на bash.org.ru проскакивала цитата про оператор +- (пусть компилятор сам решит, увеличивать или уменьшать). Так почему бы не реализовать его? =)

    PHP код:
    int operator+-(int iVal)
    {
       if ( 
    rand() % == )
          return ++
    iVal;
       else
          return --
    iVal;


Последний раз редактировалось RankoR; 09.01.2010 в 19:05. Причина: Косяк быль, насянике
RankoR вне форума  
Старый 10.01.2010, 15:54   #2
Участник
 
Аватар для metal
 
Регистрация: 31.10.2003
Сообщений: 568

Репутация: 1627
По умолчанию

Функция для приема большого объема данных (аналог recv). Код работает под Windows, для других платформ нужно изменить вызов select().

rbuf, rsz - промежуточный буфер и его размер в байтах (его можно создать и внутри функции, у меня он еще в других процедурах использовался, поэтому присутствует в параметрах)

stbuf, stsz - буфер, в который сохраняются принятые данные, и его размер (понятно, что его размер должен быть большим или равным, чем предполагаемый объем данных)

таймаут задается в миллисекундах

возвращаемое значение - число принятых байт

PHP код:
int SafeRecv(SOCKET sint nTimeoutcharrbufint rszcharstbufint stsz)
{
  
fd_set rset;
  
int offset 0rb;

  
struct timeval tv;
  
tv.tv_sec 0;
  
tv.tv_usec 1000 nTimeout;

  
FD_ZERO(&rset);
  
FD_SET(s, &rset);
  
int s_rslt select(-1, &rsetNULLNULL, &tv);
  if (
FD_ISSET(s, &rset))
  {
    
ZeroMemory((VOID*)(rbuf), rsz);
    
ZeroMemory((VOID*)(stbuf), stsz);
    
bool bDataPresent true;
    do
    {
      
FD_ZERO(&rset);
      
FD_SET(s, &rset);
      
s_rslt select(-1, &rsetNULLNULL, &tv);
      if (
s_rslt 0)
      {
        
rb recv(s, &rbuf[0], rsz0);
        if (
rb == SOCKET_ERROR)
        {
          
offset = -1;
          break;
        }
        else if (
rb == 0)
        {
          
bDataPresent false;
          break;
        }
        else
        {
          
CopyMemory(&stbuf[0] + offset, &rbuf[0], rb);
          
offset += rb;
          
ZeroMemory((VOID*)&rbuf[0], rsz);
        }
      }
    }
    while (
bDataPresent);
  }
  return (
offset);

__________________
Красивые номерки - niceuin.ru
info
icq [553-555]

Последний раз редактировалось RankoR; 10.01.2010 в 18:14.
metal вне форума  
Плюсанул metal :
Старый 10.01.2010, 18:13   #3
Почти участник
 
Регистрация: 02.02.2008
Сообщений: 1,843

Репутация: 5599
По умолчанию

metal, может я, конечно, ошибаюсь, но мне кажется, что VOID* не будет работать во всех компиляторах. Насколько я знаю, наиболее правильный из всех существующих компиллеров gcc знает только void*, но не VOID* ;)
RankoR вне форума  
Старый 12.01.2010, 19:46   #4
Почти участник
 
Регистрация: 02.02.2008
Сообщений: 1,843

Репутация: 5599
По умолчанию

  • Неявное совместное использование данных
    В Qt реализован интересный механизм с названием "Неявное совместное использование данных". Возьмем такой код
    PHP код:
    QString sStr1("Hello");
    QString sStr2 sStr1
    Какой объем памяти занимают эти 2 объекта? С первого взгляда может показаться, что его можно вычислить как sizeof(sStr1) + sizeof(sStr2). На самом деле объем используемой памяти будет меньше на 5 байт, т.к. в данном случае вторая строка равна первой, и исходя из этого компилятор принимает решение приравнять указатель на содержимое второй строки к указателю на ячейку памяти, содержащую данную строку вместо выделения новой памяти, таким образом экономя память.
    Рассмотрим такой код
    PHP код:
    QString sStr1("Hello");
    QString sStr2 sStr1;
    sStr2.append(", World!"); 
    После вызова метода append() под содержимое sStr2 выделяется новая память, и теперь указатель указывает уже на другую, новую ячейку памяти.
    Такой подход к распределению памяти существенно экономит системные ресурсы, оставаясь при этом абсолютно прозрачным для программиста.

Последний раз редактировалось RankoR; 12.01.2010 в 19:59.
RankoR вне форума  
Старый 15.01.2010, 16:59   #5
Почти участник
 
Регистрация: 02.02.2008
Сообщений: 1,843

Репутация: 5599
По умолчанию

  • Нулевые указатели и сигналы Qt
    Сигналы и слоты в Qt - достаточно интересно реализованная система обработки событий. Работает, надо сказать, безотказно, но сегодня я столкнулся с очень интересной проблемой - в произвольный момент приложение получает SIGSEGV (обращение по нулевому или несуществующему указателю). В данном софте всегда выполнялась проверка указателей (да и не могло их там быть нулевых).
    Спустя 5 часов дебага и битья головой об клаву причина была найдена.
    PHP код:
    void QOscarThread::onOscarError(quint16 errType, const QString &sError)
    {
        if ( 
    qsState == qsError )
            return;

        if ( 
    bWasOnline )
            
    emit onLogoff(loginData().first);
        
    qsState qsError;
        
    emit onError(errTypeloginData());
        
    this->quit();
        
    delete this// <- !!!

    В месте, указанном стрелкой вызывался деструктор объекта, вместе с ним уничтожался и асинхронный сокет. Сокет-то уничтожался, а вот ОС об этом ничего не знала, и к моменту, когда по идее он должен был окончательно отключиться от хоста, он уже был уничтожен (т.к. размещался он в куче с помощью оператора new). А сигнал-то был привязан к слоту этого сокета!
    Ну и возникала такая ситуация:
    • Ошибка при подключении к хосту
    • Испускается сигнал onError()
    • Сигнал обработан, сокет уничтожается
    • ОС отсоединяет свой сокет (оберткой к которому являлся наш сокет) и испускает сигнал onDisconnect()
    • Сигнал все еще привязан к слоту, ОС пытается обратиться к данному слоту по указателю... А указатель-то равен 0!
    • SIGSEGV, крах приложения

    Как решить эту проблему? В деструкторе класса сокета вызывать QObject::disconnect() для всех слотов, чтобы отсоединить все сигналы от слотов, и только после этого освобождайте память, занятую объектом.
RankoR вне форума  
Старый 16.01.2010, 18:43   #6
Почти участник
 
Регистрация: 02.02.2008
Сообщений: 1,843

Репутация: 5599
По умолчанию

  • Оптимизация работы циклов

    Возьмем такой цикл
    PHP код:
    for ( int i 0ni++ ){
       
    int iRand rand() %50 100500// <- 
       
    iSumm += iRand;

    (Содержимое цикла взято с потолка)
    В месте, указанном стрелочкой, выделяется память на 1 переменную типа int. Память выделяется и освобождается каждую итерацию цикла, т.е. n раз. При таком раскладе мы очень нефигово теряем в производительности. А теперь перепишем код немного по-другому
    PHP код:
    for ( int i 0sizeof(arr)/sizeof(int); i++ ) // <- 
       
    iSumm += arr[i]; 
    Инструкция sizeof(arr)/sizeof(int) выполняется столько раз, сколько элементов в arr. Опять же теряем время.
    Переписываем

    PHP код:
    int iSize sizeof(arr)/sizeof(int); // <- 
    for ( int i 0iSizei++ ) 
       
    iSumm += arr[i]; 
    Написали +1 строчку кода, потеряли 4 байта памяти, зато выиграли в производительности.

    Напоследок рассмотрим две функции, выполняющие аналогичные действия

    PHP код:
    char *toChars(QString sStr)
    {
       
    char cBuff[1024];
       for ( 
    int i 0sStr.Length(); i++ )
          
    cBuff[i] = sStr[i];
       return 
    cBuff
    PHP код:
    __fastcall char *toChars(const QString &sStr)
    {
       
    int iLen sStr.Length();
       
    char *cBuff = new char[iLen];
       for ( 
    int i 0iLeni++ )
          
    cBuff[i] = sStr[i];
       return 
    cBuff
    Первая функция не только работает медленнее, но и подвержена ошибке переполнения буфера.
    Вторая работает быстрее засчет нескольких оптимизаций
    • Использование соглашения о вызове как fastcall
    • Передача параметра по константной ссылке
    • Оптимизация работы цикла
RankoR вне форума  
 

Опции темы
Оценка этой теме
Оценка этой теме:

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Выкл.
HTML код Выкл.

Быстрый переход


Часовой пояс GMT +3, время: 22:31.


Перевод: zCarot
Форум Асечников © Asechka.RU

Новости Сочи