Re: Не используйте голые строки C
От: Шебеко Евгений  
Дата: 18.09.12 10:51
Оценка: -8
Нет никаких причин их использовать.
Класс строк есть в STL, каждый фреймворк содержит свой класс строк.
По эффективности все они работают также, а иногда даже лучше, чем ваш собственный код на C строках.
В любой момент вы их сможете преобразовать к константной строке C.
STl — std::string,std::wstring
VCL — AnsiString,WideString
MFC — CString

Причины для этого такие:
— Вы не забудете освободить объект.
— Вы перестаете думать о переспределении памяти и расчёте необходимого количества памяти.
— Исчезает угроза переполнения буффера.

AnsiString,CString даже содержат в себе sprintf()

Вот такой код:


        char q[1024];
        strcpy(q, "select p.street from payers as p, pl_accounts as a where a.orgid=");
        strcat(q, vOrgID.at(lsOrganisation.GetCurSel()).GetString());
        strcat(q, " and p.id=a.payerid group by p.street order by p.street;");
        if(!cur.Prepare(q))


Должен выглядеть так:

        CString q="select p.street from payers as p, pl_accounts as a where a.orgid=";
        q+=vOrgID.at(lsOrganisation.GetCurSel());
        q+" and p.id=a.payerid group by p.street order by p.street;";
        if(!cur.Prepare(q))

Если if(!cur.Prepare(q)) вдруг не соберётся, то if(!cur.Prepare(q.GetString()))
Re: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 18.09.12 11:46
Оценка: :))) :))) :)
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Сейчас приходится собеседовать много новичков.

ШЕ>Заметил что ничего в жизни не меняется.
ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.

ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень

ШЕ>ну и хотя бы лучше пройти собеседование.

ШЕ>Если кто желает что-то добавить — пожалуйста.

ШЕ>Только просьба придерживаться таких соглашений:

ШЕ>- Это должны быть грабли, на которые наступают регулярно.

ШЕ>- Краткое описание проблемы и методы её решение.
ШЕ>- Обяснение причин.
ШЕ>- Проверенный (скомпилированный) пример кода.


соседушко по офису, дебил и неряха, десятилетиями пишет код вида:

....
int * arr = new int[some_size];

if (laja)
   return;
...

delete [] arr;


Ошибка — тривиальная и дебильная, как и мой сосед: неиспользование РАИИ приводит к тому, что любой ресурс, требующий освобождения (с памятью — это самое простое)
у этого имбецила утекает в любой более/менее сложной функции, где есть какие-то вложенные блоки.

Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений.
Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.
Of course, the code must be complete enough to compile and link.
Re[2]: Не надо почленно копировать объект, используйте static_cast.
От: MasterZiv СССР  
Дата: 18.09.12 11:16
Оценка: 5 (2) +4
On 09/18/2012 02:46 PM, Шебеко Евгений wrote:

> Часто нужно присвоить потомку содержимое базового класса другого объекта.

> Неявный operator=() потомка не работает, когда присваивается базовый класс.
> Не надо почленно копировать объект, используйте static_cast.

Евгений, текст правила нужно переформулировать так:

"Никогда не нужно присваивать потомку содержимое базового класса другого
объекта. Если вы вынуждены так делать, то вам нужно пересмотреть дизайн
вашей программы."

Мне ни разу в жизни наверное не пришлость делать такой ужас.
Если же это надо делать, то нужно реализовать в наследнике
конструктор от класса-предка, и там правильно сконструировать
объект и инициализировать недостающие поля.
Posted via RSDN NNTP Server 2.1 beta
Re: forward declaration и оператор delete
От: Шебеко Евгений  
Дата: 18.09.12 10:50
Оценка: 8 (4) +1
delete не может вызвать деструктор для тех объектов, чьё объявление классов он не видит.
В таком случае просто освободится память, занимаемая объектом.

unit1.cpp:

#include <stdio.h>

struct human_t;
human_t* create_human();


int main(int argc,char** argv)
{
    human_t* v=create_human();
    printf("before delete\n");
    delete v;
    printf("after delete\n");
    return 0;
}



unit2.cpp:
#include <stdio.h>

struct human_t
{
    virtual ~human_t()
    {
        printf("~human_t()\n");
    }
};

human_t* create_human()
{
    return new human_t;
}




Вывод:

before delete
after delete



Т.е. деструктор ~human_t() не вызвается.
Re[2]: Копирующий конструктор и копирующий operator= по умолчанию.
От: PM  
Дата: 18.09.12 12:39
Оценка: +4 :)
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно.

ШЕ>Об этом надо помнить.

ШЕ>Допустим у нас есть класс, который содержит в себе указатель на свой буффер.


[тут был код очередного класса буфера]

Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.

В прикладном коде new/delete не нужен, для буфера есть std::vector<char> или его суженный аналог:

class buffer
{
public:
   buffer() {}
   buffer(char const* data, size_t size) : data_(data, data + size) {}

   bool empty() const { return data_.empty(); }

   size_t size() const { return data_.size(); }
   void resize(size_t new_size) { data_.resize(new_size); }

   char const* data() const { return data_.empty()? nullptr : &data_[0]; }
   char* data() { return data_.empty()? nullptr : &data_[0]; }
private:
   std::vector<char> data_;
};
Re: TOP граблей С++ для новичков
От: Шахтер Интернет  
Дата: 18.09.12 14:01
Оценка: +2 :)))
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Сейчас приходится собеседовать много новичков.


Вам слишком рано ещё кого-то собеседовать.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: Resource Acquisition Is Initialization
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 19.09.12 15:47
Оценка: -4 :)
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Старайтесь избегать в коде явного освобождения ресурсов.


Что-то мне подсказывает, что часть советов можно заменить простым: используйте valgrind/dtrace.
TOP граблей С++ для новичков
От: Шебеко Евгений  
Дата: 18.09.12 10:41
Оценка: 10 (3) -1
Сейчас приходится собеседовать много новичков.
Заметил что ничего в жизни не меняется.
Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.

Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень
ну и хотя бы лучше пройти собеседование.

Если кто желает что-то добавить — пожалуйста.
Только просьба придерживаться таких соглашений:

— Это должны быть грабли, на которые наступают регулярно.
— Краткое описание проблемы и методы её решение.
— Обяснение причин.
— Проверенный (скомпилированный) пример кода.



19.09.12 19:37: Перенесено из 'C/C++'
19.09.12 19:37: Перенесено из 'C/C++'
23.09.12 23:41: Перенесено из 'C/C++'
23.09.12 23:41: Перенесено из 'C/C++'
23.09.12 23:41: Перенесено из 'C/C++'
Re: TOP граблей С++ для новичков
От: uzhas Ниоткуда  
Дата: 18.09.12 11:01
Оценка: +4
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Хочу представить такие рекомендации новичкам в C++.

рекомендую это сделать в блоге: http://rsdn.ru/forum/news/4887194.flat
Автор: IT
Дата: 10.09.12
Re[2]: Поймите и используйте STL
От: MasterZiv СССР  
Дата: 18.09.12 11:24
Оценка: +1 -3
> Почему-то довольно часто приходится слышать от C++ программистов, что они не
> используют стандартную библиотеку.
> Согласитесь странно было бы слышать от программиста на JavaScript или PHP: "Я не
> использую строки" или "Я не использую массивы или ассоциативные массивы".

О!, Тут можно дооолго и нууудно распинаться. К сож. С++ тут очень сильно
отличается от других языков. Начнём с того, что стандартная библиотека языка С++
появилась много позже языка С++. Также как ни странно стандартная библиотека
языка С++, её дизайн, идёт вразрез со всеми концепциями и парадигмами языка С++,
существовавшими до неё и помимо неё. Т.е. грубо говоря, стандартная библиотека
языка С++ далеко не универсальна, поэтому применимость её достаточно ограничена.
Так что не удивляйтесь, если вам кто-то скажет, что он не применяет STL.

> Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал

> о STL.
> Каждый второй кандидат на предложение отсортировать массив, предлагает
> сортировку пузырьком!

Ну, иногда это приемлимо, а иногда это даже лучший способ.

> Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с

> использованием std::sort().

> Между тем основное, что есть в библиотеке это контейнеры и алгоритмы.


алгоритмы вообще может быть не нужны в данном приложении. Там порядка 50
процентов алгоритмов математические и статистические алгоритмы, они далеко не
во всех приложениях используются.
Posted via RSDN NNTP Server 2.1 beta
Re: Не надо почленно копировать объект, используйте static_cast.
От: Шебеко Евгений  
Дата: 18.09.12 10:46
Оценка: 4 (2) -1
Часто нужно присвоить потомку содержимое базового класса другого объекта.
Неявный operator=() потомка не работает, когда присваивается базовый класс.
Не надо почленно копировать объект, используйте static_cast.


#include <stdio.h>
#include <string>

struct human_t
{
  std::string first_name;
  std::string last_name;
  
  unsigned birth_year;
  unsigned birth_month;
  unsigned birth_day;

  unsigned birth_hour;
  unsigned birth_min;
  unsigned birth_sec;

  human_t()
  {
      birth_year=birth_month=birth_day=
      birth_hour=birth_min=birth_sec=0;
  }
};

struct women_t : public human_t
{
    std::string maiden_name;
};


int main(int argc,char** argv)
{
    human_t h;
    women_t w;

    //w=h; такая строчка не компилируется

    //часто встречается такой код
    w.first_name=h.first_name;
    w.last_name=h.last_name;

    w.birth_year=h.birth_year;
    w.birth_month=h.birth_month;
    w.birth_day=h.birth_day;

    w.birth_hour=h.birth_hour;
    w.birth_min=h.birth_min;
    w.birth_sec=h.birth_sec;

    //можно проще
    static_cast<human_t&>(w)=h;

    
    return 0;
}
Re[2]: TOP граблей С++ для новичков
От: MasterZiv СССР  
Дата: 18.09.12 18:54
Оценка: 2 (2) +1
> ШЕ>Сейчас приходится собеседовать много новичков.
>
> Вам слишком рано ещё кого-то собеседовать.

Ребята, вот зачем вот это вот всё ?
В форумах по линуксу линуксоиды сруца, какой дистр лучше.
В форумах по плюсам -- кто плюсы знает лучше ...
Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать
хоть когда-нибудь?
Posted via RSDN NNTP Server 2.1 beta
Re: Научитесь пользоваться исключениями
От: Шебеко Евгений  
Дата: 18.09.12 10:55
Оценка: -3
"Пишите так, будто ошибок в программе нет"
Подход призывает правильно пользоваться исключениями и выгодами, которые он предоставляет.
В противовес подхода, когда код ошибки возвращается из функции и обрабатывается с помощью толпы if().

Тема сложная, не берусь комментировать. Лучше почитать в книжке.
Re[3]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 19.09.12 12:05
Оценка: :)))
K>Почему он вектор не использует?

это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я
переоценил чувака.

это как, помню, в книге Хэрриота он спросил у реднекоподобных фермеров, как им понравилась последняя пьеса Шоу

кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин,
он быстро сообразил мозгом макаки, что написать это с галимым ручным управлением памятью ему уже БАНАЛЬНО НЕ ПОД СИЛУ.
в итоге все кончилось сломанным билдом не некоторых платформах — про включение заголовка и про пространства имен козел не сообразил.
Of course, the code must be complete enough to compile and link.
Re: TOP граблей С++ для новичков
От: Sashaka Россия  
Дата: 20.09.12 04:35
Оценка: +3
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Сейчас приходится собеседовать много новичков.

ШЕ>Заметил что ничего в жизни не меняется.
ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.


Зачем все это?
Как уже резонно заметили выше, новички которые это не знают и им это неинтересно — просто ничего не поймут.
Те, кто заинтересовался хорошими С++ практиками — быстро найдут ответы в книгах Саттер/Майерса/Александреску.

Шансы на то, что данный топ прочитают новички — минимален. Так что данный топик разве что вызвать C++ флуд очередной и померяться писюнами.
Re[2]: delete и delete[] различаются
От: carpenter СССР  
Дата: 23.09.12 18:04
Оценка: -3
Здравствуйте, Шебеко Евгений, Вы писали:


ШЕ>Если вы создаёте массив, то для его разрушения должны вызывать delete[].


для POD типов неактуально
Re: Книги
От: Шебеко Евгений  
Дата: 18.09.12 10:56
Оценка: 1 (1) -1
"Язык С++" "Бьёрн Страуструп" — библия программиста С++
Невероятно удачное описание, удачные примеры как самого языка, библиотеки STL, так и общего подхода к разработке ПО.


"Андрей Александреску: Современное проектирование на С++" — книга скорее вредная, чем полезная.
Она производит сильное впечатление, у читателя сразу случается приступ шаблонизма.
Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими наследование.
В результате в проекте сразу появляется куча ненужных шаблонов и шаблонных параметров.
Не обошла и меня в свое время эта тенденция.
Такие шаблоны в проекте не нужны:


template<class Loger>
class GsmModem;

template<class Loger>
class GsmModem : public GenericModem<Loger>,public igsm_modem
{
...
};

#define TEMPLATE_INFDEV \
template\
<\
  int infdev_id,\
    template <class> class CarrierPolicy,\
  class CarType,\
  template <class> class CarContainerPolicy,\
  class DevLogType,\
  template <class> class ThreadingPolicy,\
  template <class> class PollQueuePolicy,\
  template <class> class PollErrorPolicy,\
  template <class> class DirReqQueuePolicy,\
  template <class> class CustReqQueuePolicy\
>

#define INFDEV infdev<infdev_id,CarrierPolicy,CarType,CarContainerPolicy,DevLogType,ThreadingPolicy,PollQueuePolicy,PollErrorPolicy,DirReqQueuePolicy,CustReqQueuePolicy>

template
<
  int infdev_id,
    template <class> class CarrierPolicy,
  class CarType,
  template <class> class CarContainerPolicy=CarContainer,
  class DevLogType=DevLog,
  template <class> class ThreadingPolicy=SingleThread,
  template <class> class PollQueuePolicy=PollQueue,
  template <class> class PollErrorPolicy=PollError,
  template <class> class DirReqQueuePolicy=DirReqQueue,
  template <class> class CustReqQueuePolicy=CustReqQueue
>
class infdev;

Вывод. Книжку читать, она сильно меняет взгляд на понимание С++. Но не надо сразу кидаться воплощать идеи в книжке в своём проекте.
Re[3]: Копирующий конструктор и копирующий operator= по умолчанию.
От: CreatorCray  
Дата: 18.09.12 18:31
Оценка: 1 (1) +1
Здравствуйте, PM, Вы писали:

PM>Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.

Не будь так категоричен, это признак недостатка опыта.

PM>В прикладном коде new/delete не нужен, для буфера есть std::vector<char> или его суженный аналог:

В прикладном — да, но бывает ещё и не-прикладной-код
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re: Поймите и используйте STL
От: Шебеко Евгений  
Дата: 18.09.12 10:52
Оценка: +1 -1
Почему-то довольно часто приходится слышать от C++ программистов, что они не используют стандартную библиотеку.
Согласитесь странно было бы слышать от программиста на JavaScript или PHP: "Я не использую строки" или "Я не использую массивы или ассоциативные массивы".
Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.
Каждый второй кандидат на предложение отсортировать массив, предлагает сортировку пузырьком!!!
Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с использованием std::sort()

Между тем основное, что есть в библиотеке это контейнеры и алгоритмы.

Контейнеры:
std::string — строки
std::vector<> — массив
std::map<> — двоичное дерево или ассоциативный массив
std::set<> — множество. Фактически тот же std::map только хранит одни ключи, без значений.
std::hash_map<>,std::hash_set<> — тоже самое что и std::map<>,std::set<> — только не в бинарном дереве, а в хеш таблице.

Алгоритмы реализуют множество стандартных алгоритмов, знакомых нам с института. Например: поиск, поиск последовательности, двоичный поиск, сортировка, лексикографической сравнение, пересечение\объединение\вычитание множеств, уникалоьность.
Как использовать, на пальцах не объяснишь, придётся почитать книжку. хотя бы Бьёрн Страуструп "Язык C++". Часть "Стандартная библиотека"

Вот тестовое задание, которое вводит в ступор всех кандидатов:


#include <string>
#include <vector>
#include <algorithm>

struct human_t
{
    std::string first_name;
    std::string last_name;
    unsigned age;
    
    human_t()
    {
        age=0;
    }
};


int main(int argc,char** argv)
{
    std::vector<human_t> v;

    return 0;
}

Отсортировать v по фамилии и имени.


Решение довольно простое:

#include <string>
#include <vector>
#include <algorithm>

struct human_t
{
    std::string first_name;
    std::string last_name;
    unsigned age;
    
    human_t()
    {
        age=0;
    }
};

//предикат
struct human_pr
{
    inline bool operator()(const human_t& a,const human_t& b) const
    {
        if(a.last_name!=b.last_name)return a.last_name<b.last_name;
        return a.first_name<b.first_name;
    }
};


int main(int argc,char** argv)
{
    std::vector<human_t> v;

    std::sort(v.begin(),v.end(),human_pr());

    return 0;
}
Re[2]: Не используйте голые строки C
От: Abyx Россия  
Дата: 18.09.12 11:20
Оценка: +2
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>По эффективности все они работают также, а иногда даже лучше, чем ваш собственный код на C строках.

эффективности чего?
Вы стали бы писать парсер/генератор который использовал бы std::string ?
In Zen We Trust
Re[2]: Не используйте голые строки C
От: MasterZiv СССР  
Дата: 18.09.12 11:32
Оценка: +1 -1
On 09/18/2012 02:51 PM, Шебеко Евгений wrote:

> Вот такой код:

>
>
> char q[1024];
> strcpy(q,"select p.street from payers as p, pl_accounts as a where a.orgid=");
> strcat(q, vOrgID.at(lsOrganisation.GetCurSel()).GetString());
> strcat(q," and p.id=a.payerid group by p.street order by p.street;");
> if(!cur.Prepare(q))
>
>
>
> Должен выглядеть так:

Ещё очень удобно и правильно использовать вектора для таких временных буферов:

std::vector< char > q(1024);
strcpy(&q[0],"select p.street from payers as p, pl_accounts as a where a.orgid=");
strcat(&q[0], someVal);
strcat(&q[0]," and p.id=a.payerid group by p.street order by p.street;");

Также можно это использовать для временных буферов для вызова C API,
ну и конечно же в даном примере можно подтянуть и boost::printf и многое другое.
В современной версии стандартна так можно использовать и std::string вместо
std::vector.

Только один недостаток: лишняя нагрузка на хип и может быть лишная точка
синхронизации в многопоточных приложениях.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Книги
От: igna Россия  
Дата: 18.09.12 11:44
Оценка: +2
Здравствуйте, MasterZiv, Вы писали:

>> Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими

>> наследование.

MZ>+1. Очень всё правильно.


Что правильно-то? Если нужен статический полиморфизм (времени компиляции), а не динамический (времени выполнения), то как раз нужно использовать шаблоны, а не наследование.
Re[3]: Resource Acquisition Is Initialization
От: igna Россия  
Дата: 18.09.12 11:47
Оценка: :))
Здравствуйте, Abyx, Вы писали:

ШЕ>>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr

A>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr

Вот кстати пример того, почему лучше все-таки читать советы настоящих, а не доморощенных гуру.
Re[4]: delete и delete[] различаются
От: uzhas Ниоткуда  
Дата: 18.09.12 15:32
Оценка: +2
Здравствуйте, PlusMyTwitterFace, Вы писали:

PMT>За что минус поясните? Мне не жалко, а действительно интересно.


падение программы на delete — это крайне редкое событие имхо
в моей практике я видел такие последствия:
1) утечка памяти, если массив содержит сложные объекты (из-за того, что не вызовутся деструкторы). при этом память под объекты (не включая их мемберов) будет освобождена
2) никаких проблем, если массив состоит из простых типов или POD-ов
то есть в таком коде на практике нет проблем:
int* x = new int[200];
delete x;

3) никаких проблем, если массив состоит из объектов, которые в деструкторах ничего умного не делают и не освобождают (включая автоматически сгенерированные деструкторы)
мой опят ограничен лишь работой с VS+gcc, возможно, где-то есть более печальные последствия из-за неправильного delete\delete[], но я не слышал о подобных проблемах
Re[7]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 23:08
Оценка: -2
AS>>ptrdtor UNIQNAME(...);
AS>>typedef std::shared_ptr<void> ptrdtor;
P>это как пушкой по воробьям. он же thread-safe ref-count

Э... вопрос то как бы про другое был )
Работает? — Да. RAII? — Тоже да. Просто? — вроде как более чем.
Коротко и понятно без реализации? — ... ну ты же понял.

P>тем более в C++11 можно так


Ну, классно да. Десятая студия прожуёт? )
Re[4]: TOP граблей С++ для новичков
От: rg45 СССР  
Дата: 19.09.12 09:05
Оценка: +1 :)
Здравствуйте, wander, Вы писали:

W>Здравствуйте, MasterZiv, Вы писали:


MZ>> Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать

MZ>> хоть когда-нибудь?

W>Гнев на технологии лучше тоже не обращать. Технологии надо анализировать и оценивать и, следовательно, применять или не применять по результатам. А гневаться лучше на что-нибудь другое.


А лучше вообще не гневаться, гнев — это грех.
--
Справедливость выше закона. А человечность выше справедливости.
Re[7]: Resource Acquisition Is Initialization
От: igna Россия  
Дата: 20.09.12 07:32
Оценка: +1 :)
Здравствуйте, Кодт, Вы писали:

К>Саттерс — это семья Саттеров?




К>Кстати, напоминаю о существовании правил форума, где попрекание собеседников нехваткой квалификации не приветствуется.


Нет, ну "не гуру" это не нехватка квалификации. А то так можно дойти до того, что сказать человеку, что он не гений, будет восприниматься как оскорбление.
Re[3]: Поймите и используйте STL
От: Piko  
Дата: 18.09.12 11:59
Оценка: 4 (1)
Здравствуйте, Abyx, Вы писали:

A>если С++03 — зачем функтор если достаточно функции


насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими.
А как C++98 и C++03 отличаются в этом месте?
Re[5]: delete и delete[] различаются
От: Кодт Россия  
Дата: 19.09.12 18:33
Оценка: 4 (1)
Здравствуйте, uzhas, Вы писали:

U>падение программы на delete — это крайне редкое событие имхо


Да легко!
struct foo { virtual ~foo() {} };

int main()
{
  delete new foo[2];
}

Немедленно валится
*** glibc detected *** ./x: munmap_chunk(): invalid pointer: 0x09ac900c ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x73e42)[0x8a9e42]
/lib/i386-linux-gnu/libc.so.6(+0x74525)[0x8aa525]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0x54c51f]
./x[0x8048708]
./x[0x80486b6]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x84f4d3]
./x[0x80484d1]

А всё потому, что выделенный блок памяти (0x09ac9008) имеет отрицательное смещение от собственно указателя на первый элемент (0x09ac900c). Деструктор первого элемента отрабатывает нормально, а вот собственно освобождение памяти обламывается.
Перекуём баги на фичи!
Re: Виртуальный деструктор
От: Шебеко Евгений  
Дата: 18.09.12 10:48
Оценка: 1 (1)
Если вы планируете удалять производный класс, используя указатель на базовый класс, вы должны сделать дестурктор базового класса виртуальным.
Иначе деструктор потомка не будет вызван.
Это также касается случая, когда в вашем производном классе нет явного деструктора. В нём могут быть переменные (например, типа std::string) для которых нужно вызвать деструктор.


#include <stdio.h>
#include <string>

struct human_t
{
};

struct women_t : public human_t
{
    std::string maiden_name;

    ~women_t()
    {
        printf("~women_t()\n");
    }

};


int main(int argc,char** argv)
{
    human_t* v=new women_t;
    printf("before delete\n");
    delete v;
    printf("after delete\n");
    return 0;
}


Вывод:

before delete
after delete



Если изменить на:

#include <stdio.h>
#include <string>

struct human_t
{
    virtual ~human_t(){}
};

struct women_t : public human_t
{
    std::string maiden_name;

    ~women_t()
    {
        printf("~women_t()\n");
    }

};


int main(int argc,char** argv)
{
    human_t* v=new women_t;
    printf("before delete\n");
    delete v;
    printf("after delete\n");
    return 0;
}


То вывод будет таким, как ожидалось:

before delete
~women_t()
after delete
Re[3]: Копирующий конструктор и копирующий operator= по умолчанию.
От: Piko  
Дата: 18.09.12 12:43
Оценка: 1 (1)
Здравствуйте, PM, Вы писали:

PM>[тут был код очередного класса буфера]

PM>Для меня new вне конструктора умного указателя (std::shared_ptr, std::unique_ptr или их аналогов из Boost) — признак плохого кода.

для меня new вне make_XXX для умного указателя — грабли. (ещё new легален в своих контейнерах)
используй make_unique, make_shared http://herbsutter.com/gotw/_102/
Re[5]: delete и delete[] различаются
От: PlusMyTwitterFace  
Дата: 18.09.12 15:47
Оценка: 1 (1)
Да, согласен, извиняюсь. Но UB имеет место быть, а дальнейшее обсуждение UB — это уже что-то бессмысленное, на мой взгляд.
Re: Стандарты программирования на С++
От: igna Россия  
Дата: 18.09.12 11:05
Оценка: +1
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Хочу представить такие рекомендации новичкам в C++.


А чем твои советы лучше чем Стандарты программирования на С++, <i>Герб Саттер, Андрей Александреску</i>?
Re[2]: Стандарты программирования на С++
От: slava_phirsov Россия  
Дата: 18.09.12 11:09
Оценка: +1
Здравствуйте, igna, Вы писали:

I>А чем твои советы лучше чем Стандарты программирования на С++, <i>Герб Саттер, Андрей Александреску</i>?


Практически все советы ТС можно найти у моего любимого Майерса ("Effective C++", "More effective C++").
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[2]: Поймите и используйте STL
От: slava_phirsov Россия  
Дата: 18.09.12 11:16
Оценка: +1
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Почему-то довольно часто приходится слышать от C++ программистов, что они не используют стандартную библиотеку.


Очень многие при использовании фреймворка стараются использовать только те элементы стандартной библиотеки, которых нет в используемом фреймворке. В результате и получаем "не используют стандартную библиотеку".


ШЕ>Зато каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.


Это прискорбно. С другой стороны, если заниматься буквоедством, и, ЕМНИП, такого слова STL больше нет. Есть просто стандартная библиотека C++, включившая в себя то, что раньше называлось STL (если я не прав -- поправьте).
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[3]: Стандарты программирования на С++
От: igna Россия  
Дата: 18.09.12 11:20
Оценка: +1
Здравствуйте, slava_phirsov, Вы писали:

_>Практически все советы ТС можно найти у моего любимого Майерса ("Effective C++", "More effective C++").


Вопрос-то не в том, а в том, зачем нужны советы от Шебеко.
Re[2]: Resource Acquisition Is Initialization
От: Abyx Россия  
Дата: 18.09.12 11:27
Оценка: +1
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr

std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr

ШЕ>Предпочтительнее использовать shared_ptr<>, т.к. внутри него есть счётчик ссылок, что позволяет его безопасно копировать и хранить в контейнерах.

ниразу не предпочтительнее. он потокобезопасный и потому очень медленный, так что предпочтительнее — std::unique_ptr.
к томуже в большинстве случаев общее владение объектом не нужно.
In Zen We Trust
Re[4]: Стандарты программирования на С++
От: MasterZiv СССР  
Дата: 18.09.12 11:36
Оценка: +1
> Вопрос-то не в том, а в том, зачем нужны советы от Шебеко.

ПО-моему так всё очень правильно и здорово. Не важно, от кого советы, важно,
чтобы были правильные. А еси повторяются -- не страшно, лишний раз кто-то
прочитает -- хуже не будет.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: Стандарты программирования на С++
От: igna Россия  
Дата: 18.09.12 11:39
Оценка: +1
Здравствуйте, MasterZiv, Вы писали:

MZ>ПО-моему так всё очень правильно и здорово. Не важно, от кого советы, важно,

MZ>чтобы были правильные. А еси повторяются -- не страшно, лишний раз кто-то
MZ>прочитает -- хуже не будет.

Да нет, просто в книге все собрано и ссылки на Мейерса, Саттера, Страуструпа и других, если кого какая тема заинтересовала и хочется поподробнее. И книга сама тонюсенькая, чуть больше 200 страниц.
Re[3]: TOP граблей С++ для новичков
От: igna Россия  
Дата: 18.09.12 11:55
Оценка: +1
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>ой, я не заметил, что ты уже писал про такое. но, короче, когда человек пишет в стиле "назад в 1982 к С с классами" — это его ежедневный "паттерн" — неспособность освободить ресурсы.


А в С с классами не было деструктора?
Re[5]: Поймите и используйте STL
От: Piko  
Дата: 18.09.12 12:30
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>>>если С++03 — зачем функтор если достаточно функции

P>>насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими.
A>да, в каких-то версиях MSVC именно так (хз как в MSVC11), а в g++ вроде функция инлайнится, IIRC

функция конечно может инлайнится — и она скорей всего нормально инлайнится во многих версиях msvc, и gcc, но у функтора намного больше шансов.
написать лишние двадцать буковок для функтора — не проблема, большой смысловой нагрузки они не несут, ошибится в них трудно
Re: TOP граблей С++ для новичков
От: PM  
Дата: 18.09.12 12:54
Оценка: +1
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Сейчас приходится собеседовать много новичков.

ШЕ>Заметил что ничего в жизни не меняется.
ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.

ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень

ШЕ>ну и хотя бы лучше пройти собеседование.

ШЕ>Если кто желает что-то добавить — пожалуйста.

ШЕ>Только просьба придерживаться таких соглашений:

ШЕ>- Это должны быть грабли, на которые наступают регулярно.

ШЕ>- Краткое описание проблемы и методы её решение.
ШЕ>- Обяснение причин.
ШЕ>- Проверенный (скомпилированный) пример кода.

Я было начал отвечать на ваши сообщения, но потом понял, что пересказываю содержание книг Майерса и Саттера. Новичкам это бесполезно — они еще не наступили на все грабли, опытным С++ программистам это уже 10 лет как не интересно.

Так что новичкам я бы порекомендовал читать умные книги и писать реальный код
Re[2]: delete и delete[] различаются
От: PlusMyTwitterFace  
Дата: 18.09.12 14:51
Оценка: -1
ШЕ>Либо осовободится только один объект, либо программа упадёт.

Будет UB. Хотя, как правило, именно указанное Вами поведение встречается в большинстве реализаций.
Re[2]: Копирующий конструктор и копирующий operator= по умолчанию.
От: Masterkent  
Дата: 18.09.12 15:40
Оценка: +1
Шебеко Евгений:

ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно.

ШЕ>Об этом надо помнить.
....
ШЕ>Решение — сделать private копирующий конструктор и operator=. При этом достаточно их просто объявить, тело функций добавлять не надо.

C++11 пока, наверное, мало востребован, но, давая общие рекомендации по C++, совсем его игнорировать не стоит. В данном случае можно явно объявить копирующие функции как deleted, либо, что ещё лучше, добавить в класс пользовательский конструктор перемещения и (опционально) перемещающий оператор присваивания (неявно объявленные копирующие конструктор и оператор присваивания при этом автоматом будут считаться deleted, хотя для некоторых недоразвитых компиляторов =delete всё же придётся прописывать вручную).
Re[2]: Не надо почленно копировать объект, используйте static_cast.
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 19.09.12 09:33
Оценка: -1
Здравствуйте, Шебеко Евгений, Вы писали:

Ещё это классический пример т.н срезки.
Sic luceat lux!
Re[5]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 19.09.12 13:41
Оценка: :)
L_L>>это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я
L_L>>переоценил чувака.

K>Да вообще всякое бывает. Может такое было оправдано? Хотя в 99% проще заюзать стл.


В коде, который они лобали в 95-ом 96-ом — воплне возможно. Плохо, что с тех пор С++ для них таким, как он был в начале девяностых

K>Странно, что был выбран вектор для этого.


Вектор ему лучше всего подошел.

K>Зато он наверное все собеседования прошёл.


в этом году было какое-то подобие аттестации для сотрудников типа него (у него очень хорошая позиция-контракт, он практически бессмертен) — он прибежал с нее, подпрыгивая от радости,
из чего я сделал вывод, что все зашибись и удачно прошло.
Of course, the code must be complete enough to compile and link.
Re[5]: TOP граблей С++ для новичков
От: Кодт Россия  
Дата: 21.09.12 20:58
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

_>В конструкторе всегда таблица от текущего класса и в деструкторе тоже.

_>Именно эта особенность приводит к граблям при параллельном исполнении.

На самом деле, грабли там в кривом дизайне и перекрытии времени жизни.
Ну нельзя делать так, что время жизни объекта-работодателя (до входа в деструктор) было короче, чем время жизни потока-подчинённого.
А если очень-очень хочется задействовать RAII, чтобы поток гасился из деструктора, — так не надо смешивать объект-работодатель и RAII-сторож.
Да, получится двухфазная деинициализация.

И вообще, ООП конкретно в этом месте больше мешает, чем помогает, — провоцируя на антипаттерн самоубийцы. ФП-подход, где данные для потока передаются в замыкание и там живут до самой смерти, — более естественнен.
Перекуём баги на фичи!
Re: Копирующий конструктор и копирующий operator= по умолчанию.
От: Шебеко Евгений  
Дата: 18.09.12 10:43
Оценка:
Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно.
Об этом надо помнить.

Допустим у нас есть класс, который содержит в себе указатель на свой буффер.



class buf_t
{
  unsigned char* data;
public:
  buf_t(size_t buf_size)
  {
    data=new unsigned char[buf_size];
    printf("buf_t(): data=%p\n",data);
  }

  ~buf_t()
  {
    printf("~buf_t(): data=%p\n",data);
    delete[] data;
  }

};


Легко ошибиться и выполнить присваивание или вызвать копирующий конструктор для такого объекта.
Вот такой код запросто скомпилируется и будет работать неправильно.


int main(int argc,char** argv)
{
  buf_t a(1000);

  buf_t b(a);

  buf_t c(500);
  c=a;


  return 0;
}


Вывод программы будет такой:


buf_t(): data=00902DCC
buf_t(): data=009031B8
~buf_t(): data=00902DCC
~buf_t(): data=00902DCC
~buf_t(): data=00902DCC



Т.е. мы присвоили указатель data объекта a объектам b и c.
В результате у нас 3 раза освободился один и тот же указатель, а data объекта c вообще потерялся.

Решение — сделать private копирующий конструктор и operator=. При этом достаточно их просто объявить, тело функций добавлять не надо.


class buf_t
{
  unsigned char* data;
public:
  buf_t(size_t buf_size)
  {
    data=new unsigned char[buf_size];
    printf("buf_t(): data=%p\n",data);
  }

  ~buf_t()
  {
    printf("~buf_t(): data=%p\n",data);
    delete[] data;
  }

private:
    buf_t(const buf_t&);
    void operator=(const buf_t&);

};
Re: delete и delete[] различаются
От: Шебеко Евгений  
Дата: 18.09.12 10:44
Оценка:
Если вы создаёте объект, то для его разрушения должны вызывать delete.
Если вы создаёте массив, то для его разрушения должны вызывать delete[].
Иначе ваш код будет работать неправильно.
Для компилятора указатель на объект и указатель на массив неразличимы, поэтому это ваша проблема следить, какой delete вызвать.


item_t* v= new item_t;
...
delete v;

item_t* v= new item_t[100];
...
delete[] v;


Что будет, если для массивов вызвать обычный delete?
Либо осовободится только один объект, либо программа упадёт.
Можете сами в этом убедится, выполнив такой код:

#include <stdio.h>
#include <string>

struct item_t
{
  std::string name;

  item_t()
  {
    printf("item_t()\n");
  }

  ~item_t()
  {
    printf("~item_t()\n");
  }
};


int main(int argc,char** argv)
{
  item_t* v=new item_t[100];
  delete v;

  return 0;
}
Re: Resource Acquisition Is Initialization
От: Шебеко Евгений  
Дата: 18.09.12 10:54
Оценка:
здесь

Старайтесь избегать в коде явного освобождения ресурсов.
Причины для этого такие:
— Вы можете выйти из области видимости (например, return посреди функции), забыв освободить ресурс.
— В функции или в вызываемых функциях может произойти исключение.
Поэтому либо ресурс останется неосвобождённым, либо придётся расставлять try\catch после каждой инициализации ресурсов в функции.


//Пример    автоматического вызова fclose()
class file_hldr
{
    file_hldr(const file_hldr&);
    void operator=(const file_hldr&);
public:
    FILE* f;
    file_hldr(FILE* _f) {f=_f;}
    ~file_hldr(){if(f)fclose(f);}
};

//Использовать так:
void foo()
{
    FILE* f=fopen("data.txt","rb");
    file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
    ...
}


Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr
Предпочтительнее использовать shared_ptr<>, т.к. внутри него есть счётчик ссылок, что позволяет его безопасно копировать и хранить в контейнерах.
Для строк std::string или тот класс строк, который использует ваш фреймворк. CString, например.
Для массивов, с некоторыми оговорками, можно использовать std::vector<>. Даже в том случае, когда нужно получить прямой указатель на массив объектов.
Для остальных ресурсов, часто фреймворк, который вы используете, уже предоставляет классы-обёртки. Поищите их и пользуйтесь. Например, CFile,CPen,CBrush, CDC и т.д.
Для ваших собственных ресурсов вполне можно написать такую же поделку, как я привёл выше.
Re[2]: Не используйте голые строки C
От: slava_phirsov Россия  
Дата: 18.09.12 11:11
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Нет никаких причин их использовать.


Вообще-то нет никакого разумного способа обойтись без их использования. Ибо любой фреймворочный класс строк инициализируется из C-строки. Ну это так, 5 коп.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[2]: Поймите и используйте STL
От: Abyx Россия  
Дата: 18.09.12 11:24
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>std::hash_map<>,std::hash_set<>


нету таких классов в std

ШЕ>//предикат

ШЕ>struct human_pr
ШЕ>{
ШЕ> inline bool operator()(const human_t& a,const human_t& b) const
ШЕ> {
ШЕ> if(a.last_name!=b.last_name)return a.last_name<b.last_name;
ШЕ> return a.first_name<b.first_name;
ШЕ> }
ШЕ>};
ШЕ>


если С++03 — зачем функтор если достаточно функции
если С++ — должна быть лямбда.
In Zen We Trust
Re[2]: Книги
От: MasterZiv СССР  
Дата: 18.09.12 11:25
Оценка:
On 09/18/2012 02:56 PM, Шебеко Евгений wrote:

> "Андрей Александреску: Современное проектирование на С++" — книга скорее

> вредная, чем полезная.
> Она производит сильное впечатление, у читателя сразу случается приступ шаблонизма.
> Хотя сам Александреску призывает разумно использовать шаблоны и не заменять ими
> наследование.

+1. Очень всё правильно.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 18.09.12 11:49
Оценка:
ой, я не заметил, что ты уже писал про такое. но, короче, когда человек пишет в стиле "назад в 1982 к С с классами" — это его ежедневный "паттерн" — неспособность освободить ресурсы.
Of course, the code must be complete enough to compile and link.
Re[4]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 18.09.12 12:06
Оценка:
I>А в С с классами не было деструктора?

странно, что ты не понял — я не об особенностях определенной реализации С++ говорю, а о том, что люди на С++ пишут, как будто у них С или что похуже.
Of course, the code must be complete enough to compile and link.
Re[2]: Поймите и используйте STL
От: Сыроежка  
Дата: 18.09.12 12:07
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Каждый второй кандидат на предложение отсортировать массив, предлагает сортировку пузырьком!!!

ШЕ>Только два кандидата, с помощью гугла, смогли дать более-менее рабочий код с использованием std::sort()

А я знаю сортировку выбором!

Если бы мне предложили отсортировать контейнер, то я специально использовал бы сортировку выбором с использованием станалртных алгоритмов!

ШЕ>Вот тестовое задание, которое вводит в ступор всех кандидатов:



ШЕ>
ШЕ>#include <string>
ШЕ>#include <vector>
ШЕ>#include <algorithm>

ШЕ>struct human_t
ШЕ>{
ШЕ>    std::string first_name;
ШЕ>    std::string last_name;
ШЕ>    unsigned age;
    
ШЕ>    human_t()
ШЕ>    {
ШЕ>        age=0;
ШЕ>    }
ШЕ>};


ШЕ>int main(int argc,char** argv)
ШЕ>{
ШЕ>    std::vector<human_t> v;

ШЕ>    return 0;
ШЕ>}

ШЕ>Отсортировать v по фамилии и имени.

ШЕ>


ШЕ>Решение довольно простое:


ШЕ>
ШЕ>#include <string>
ШЕ>#include <vector>
ШЕ>#include <algorithm>

ШЕ>struct human_t
ШЕ>{
ШЕ>    std::string first_name;
ШЕ>    std::string last_name;
ШЕ>    unsigned age;
    
ШЕ>    human_t()
ШЕ>    {
ШЕ>        age=0;
ШЕ>    }
ШЕ>};

ШЕ>//предикат
ШЕ>struct human_pr
ШЕ>{
ШЕ>    inline bool operator()(const human_t& a,const human_t& b) const
ШЕ>    {
ШЕ>        if(a.last_name!=b.last_name)return a.last_name<b.last_name;
ШЕ>        return a.first_name<b.first_name;
ШЕ>    }
ШЕ>};
ШЕ>

ШЕ>int main(int argc,char** argv)
ШЕ>{
ШЕ>    std::vector<human_t> v;

ШЕ>    std::sort(v.begin(),v.end(),human_pr());
ШЕ>
ШЕ>    return 0;
ШЕ>}

ШЕ>



Вообще-то у std::pair уже определен оператор <. Поэтому не надо изобретать велосипед, а использовать реализацию этого оператора.
Меня можно встретить на www.cpp.forum24.ru
Re[3]: Поймите и используйте STL
От: Сыроежка  
Дата: 18.09.12 12:15
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, Шебеко Евгений, Вы писали:


ШЕ>>std::hash_map<>,std::hash_set<>


A>нету таких классов в std


ШЕ>>//предикат

ШЕ>>struct human_pr
ШЕ>>{
ШЕ>> inline bool operator()(const human_t& a,const human_t& b) const
ШЕ>> {
ШЕ>> if(a.last_name!=b.last_name)return a.last_name<b.last_name;
ШЕ>> return a.first_name<b.first_name;
ШЕ>> }
ШЕ>>};
ШЕ>>


A>если С++03 — зачем функтор если достаточно функции

A>если С++ — должна быть лямбда.

К функции вы не сможете применить адаптеры, как, например, std::not1.

Лямбда выражения целесообразно применять, лишь когда они используется в какой-то локальной области кода. Если же они захватывают локальные переменные, а ич функциональность должна использоваться в нескольких местах кода и единиц трансляции, то лучше использовать функциональные объекты.
Меня можно встретить на www.cpp.forum24.ru
Re[4]: Поймите и используйте STL
От: Abyx Россия  
Дата: 18.09.12 12:17
Оценка:
Здравствуйте, Piko, Вы писали:

A>>если С++03 — зачем функтор если достаточно функции


P>насколько я знаю фуктор подставляется в параметр шаблона как тип, то есть чистый compile-time, а функция как указатель на семейство функций со всеми вытекающими.


да, в каких-то версиях MSVC именно так (хз как в MSVC11), а в g++ вроде функция инлайнится, IIRC
In Zen We Trust
Re[5]: TOP граблей С++ для новичков
От: igna Россия  
Дата: 18.09.12 12:25
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>странно, что ты не понял — я не об особенностях определенной реализации С++ говорю, а о том, что люди на С++ пишут, как будто у них С или что похуже.


Мне в самом деле стало интересно, с самого ли начала в C++ или C с классами был деструктор.

А вот по поводу "как будто у них С" несогласен. На C, когда в функции выделяются русурсы, return как правило один — в конце. (Или его вообще нет, если функция ничего не возвращает.)
Re[4]: Поймите и используйте STL
От: Piko  
Дата: 18.09.12 12:39
Оценка:
Здравствуйте, Сыроежка, Вы писали:

A>>если С++03 — зачем функтор если достаточно функции

A>>если С++ — должна быть лямбда.
С>К функции вы не сможете применить адаптеры, как, например, std::not1.

1. есть std::ptr_fun.
2. к human_pr not1 не применишь, во-первых он бинарный, во-вторых он не определяет argument_type.
3. нафига not1 в данной конкретной задаче?

С>Лямбда выражения целесообразно применять, лишь когда они используется в какой-то локальной области кода. Если же они захватывают локальные переменные, а ич функциональность должна использоваться в нескольких местах кода и единиц трансляции, то лучше использовать функциональные объекты.


Я удивлён, но мысль у тебя верная, браво!
Вот только к обсуждаемому примеру не относится, там лямбду использовать целесообразно
Re[2]: Поймите и используйте STL
От: ML380 Земля  
Дата: 18.09.12 12:45
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>каждый четвёртый кандидат на должность C++ программиста, никогда не слышал о STL.


Странно. А выборка у Вас большая?
Возможно, это связано с тем, что не везде, где используется С++ получается использовать STL.
Или не используют именно по религиозным соображениям?
Re[3]: Поймите и используйте STL
От: ML380 Земля  
Дата: 18.09.12 13:02
Оценка:
Здравствуйте, Abyx, Вы писали:

A>если С++03 — зачем функтор если достаточно функции


1) Если используются биндеры или адаптеры
2) Функтор умеет хранить значения, что иногда удобно. Например for_each возвращает объект переданный в качестве функции. Правда тут нужно быть осторожным, точно быть уверенным в том, что передаваесый объект не копируется внутри алгоритма.
3) Часто это более эфективно т.к. вызов можно сделать встраеваемым
Re[4]: Поймите и используйте STL
От: Abyx Россия  
Дата: 18.09.12 13:11
Оценка:
Здравствуйте, ML380, Вы писали:

ML>Здравствуйте, Abyx, Вы писали:


A>>если С++03 — зачем функтор если достаточно функции


ML>1) Если используются биндеры или адаптеры

ML>2) Функтор умеет хранить значения, что иногда удобно. Например for_each возвращает объект переданный в качестве функции. Правда тут нужно быть осторожным, точно быть уверенным в том, что передаваесый объект не копируется внутри алгоритма.

не надо вырезать код из моего поста.
зачем в *том* коде функтор?

ML>3) Часто это более эфективно т.к. вызов можно сделать встраеваемым

зависит от компилятора.
In Zen We Trust
Re[6]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 18.09.12 13:19
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Lorenzo_LAMAS, Вы писали:


L_L>>странно, что ты не понял — я не об особенностях определенной реализации С++ говорю, а о том, что люди на С++ пишут, как будто у них С или что похуже.


I>Мне в самом деле стало интересно, с самого ли начала в C++ или C с классами был деструктор.


I>А вот по поводу "как будто у них С" несогласен. На C, когда в функции выделяются русурсы, return как правило один — в конце. (Или его вообще нет, если функция ничего не возвращает.)


ну вот у удода — какой-то гибрид из С и С++, который можно назвать условно С с классами: вроде классы есть, а ничего больше от С++ он и не позаимствовал,
ресурсы освобождает вручную, как в С, а техники С с одним местом выхода — он и не знал никогда. недо С, недо С++, высер.
Of course, the code must be complete enough to compile and link.
Re[2]: forward declaration и оператор delete
От: rg45 СССР  
Дата: 18.09.12 13:23
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>delete не может вызвать деструктор для тех объектов, чьё объявление классов он не видит.


Что ты понимаешь под "объявлением класса"?
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Виртуальный деструктор
От: PlusMyTwitterFace  
Дата: 18.09.12 14:51
Оценка:
ШЕ>Иначе деструктор потомка не будет вызван.

Опять же будет UB. Хотя, как правило, именно указанное Вами поведение встречается в большинстве реализаций.
Re[3]: delete и delete[] различаются
От: PlusMyTwitterFace  
Дата: 18.09.12 15:21
Оценка:
За что минус поясните? Мне не жалко, а действительно интересно.
Re[4]: Книги
От: MasterZiv СССР  
Дата: 18.09.12 15:34
Оценка:
> Что правильно-то? Если нужен статический полиморфизм (времени компиляции), а не
> динамический (времени выполнения), то как раз нужно использовать шаблоны, а не
> наследование.

О книге сказано правильно.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: delete и delete[] различаются
От: Vzhyk  
Дата: 18.09.12 15:39
Оценка:
18.09.2012 13:44, Шебеко Евгений пишет:

> Если вы создаёте объект, то для его разрушения должны вызывать delete.

> Если вы создаёте массив, то для его разрушения должны вызывать delete[].
>
> item_t* v=new item_t;
> ...
> delete v;
>
> item_t* v=new item_t[100];
> ...
> delete[] v;
Опять же, лучше использовать какой контейнер или *_ptr какой.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Поймите и используйте STL
От: Vzhyk  
Дата: 18.09.12 15:47
Оценка:
18.09.2012 13:52, Шебеко Евгений пишет:

> Почему-то довольно часто приходится слышать от C++ программистов, что

> они не используют стандартную библиотеку.
Потому что здесь количество велосипедопесателей зашкаливает в отличие от
JavaScript или PHP.

> Зато каждый четвёртый кандидат на должность C++ программиста, никогда не

> слышал о STL.
Зато они могут написать сходу различные виду сортировки небось.

> Каждый второй кандидат на предложение отсортировать массив, предлагает

> сортировку пузырьком!!!
> Только два кандидата, с помощью гугла, смогли дать более-менее рабочий
> код с использованием std::sort()
Потому что куча клоунов на собеседованиях именно просят реализовать
сортировку (об этом тут было море срачей) и очень обижаются, если им
предлагают библиотечный sort.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: Книги
От: igna Россия  
Дата: 18.09.12 15:51
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>О книге сказано правильно.


Ну ты же сказал "все правильно", значит и это: "Александреску призывает разумно использовать шаблоны и не заменять ими наследование."
Re[2]: TOP граблей С++ для новичков
От: CreatorCray  
Дата: 18.09.12 18:31
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>соседушко по офису, дебил и неряха, десятилетиями пишет код вида:

L_L>Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений.
L_L>Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.

А куда смотрит тимлид и прочий менеджмент?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[2]: Resource Acquisition Is Initialization
От: VladFein США  
Дата: 18.09.12 20:05
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>
ШЕ>void foo()
ШЕ>{
ШЕ>    FILE* f=fopen("data.txt","rb");
ШЕ>    file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ>    ...
ШЕ>}
ШЕ>


Разве это пример RAII?
Вот если бы Ваш file_hldr сам открывал файл...
Re[3]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 21:23
Оценка:
Здравствуйте, VladFein, Вы писали:

ШЕ>>
ШЕ>>void foo()
ШЕ>>{
ШЕ>>    FILE* f=fopen("data.txt","rb");
ШЕ>>    file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ>>    ...
ШЕ>>}
ШЕ>>


VF>Разве это пример RAII?

VF>Вот если бы Ваш file_hldr сам открывал файл...

То есть я так понимаю такой код ни есть RAII:

int main() {
  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
  printf("file: %p",f);
  //...
}
Re[4]: Resource Acquisition Is Initialization
От: VladFein США  
Дата: 18.09.12 21:38
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>То есть я так понимаю такой код ни есть RAII:


AS>
AS>int main() {
AS>  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
AS>  printf("file: %p",f);
AS>  //...
AS>} 
AS>


Что такое ptrdtor? UNIQNAME? call_ifn0?
Re[5]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:07
Оценка:
Здравствуйте, VladFein, Вы писали:

AS>>То есть я так понимаю такой код ни есть RAII:

AS>>
AS>>int main() {
AS>>  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
AS>>  printf("file: %p",f);
AS>>  //...
AS>>} 
AS>>

VF>Что такое ptrdtor? UNIQNAME? call_ifn0?

ну, судя по использованию:
ptrdtor — что-то типа scoped_ptr, но хранящий "deleter"
UNIQNAME — макрос раскрывающийся в типа уникальный идентификатор.
call_ifn0 — унарный функтор, сравнивающий в operator() аргумент на 0, и если не ноль то вызывает функтор переданный в конструкторе с этим аргументом.
Re[5]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 22:40
Оценка:
VF>Что такое ptrdtor? UNIQNAME? call_ifn0?

А что, знание реализации как-то меняет семантику RAII? Впрочем, ИМХО всё более чем очевидно:
#include <memory>

template <class T,class R> struct call_ifn0_t { 
  R (*f)(T); 
  void operator()(T t) { if ( t ) f(t); } 
};

template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
  call_ifn0_t<T,R> q = { f }; 
  return q; 
}

typedef std::shared_ptr<void> ptrdtor;
#define MACRO_CONCAT1(a,b) a##b
#define MACRO_CONCAT(a,b) MACRO_CONCAT1(a,b) 
#define UNIQNAME MACRO_CONCAT(local_uniqname_at_line_,__LINE__)
Re[6]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:55
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>ptrdtor UNIQNAME(...);

и
AS>typedef std::shared_ptr<void> ptrdtor;

это как пушкой по воробьям. он же thread-safe ref-count
Re[6]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:58
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>
AS>template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
AS>  call_ifn0_t<T,R> q = { f }; 
AS>  return q; 
AS>}
AS>


да, и зачем nrvo, а не?
тем более в C++11 можно так:
template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
  return { f }; 
}
Re[7]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:58
Оценка:
P>да, и зачем nrvo, а не?
а не rvo
Re[8]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:26
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>Э... вопрос то как бы про другое был )


не спорю

P>>тем более в C++11 можно так

AS>Ну, классно да. Десятая студия прожуёт? )

десятая давится, одиннадцатая — давится, gcc-4.5.1 — жуёт.
с одиннадцатой вообще прикол, она на fclose выдаёт, ошибку компиляции, по дефолту! всё, приплыли

Error 1 error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.


в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?
Re[9]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:28
Оценка:
Здравствуйте, Piko, Вы писали:

P>с одиннадцатой вообще прикол, она на fclose выдаёт, ошибку компиляции, по дефолту! всё, приплыли


не, сорри, мой косяк, кинул не в тот проект.. у меня просто по умолчанию варниги до ошибок аппятся
Re[9]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 23:45
Оценка:
P>в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?

Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.
Re[10]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:54
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.


может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..
Re[11]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 00:19
Оценка:
P>может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
Какая разница? Это просто указатель. Мало ли как он представлен и во что завёрнут.

P>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..

Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.

gcc / return { f };
cl / return q;

gcc -O0
leaq    fclose(%rip), %rcx
call    _Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E
movq    %rax, 24(%rbp)


cl -Od
push     OFFSET _fclose
call     ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add     esp, 4
mov     DWORD PTR $T65617[ebp], eax


gcc -O2, __attribute__((noinline))
leaq    fclose(%rip), %rcx
call    _Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E
movq    %rax, 152(%rsp)

_Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E:
movq    %rcx, %rax
ret


cl -O2, __declspec(noinline)
push     OFFSET _fclose
call     ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
mov     edi, eax

??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z PROC ;
mov     eax, DWORD PTR _f$[esp-4]
ret      0


Чёт не вижу принципиальной разницы.
Re[12]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 01:00
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

P>>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..

AS>Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.

при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.

вот rvo, msvc2010 debug:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR $T20367[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
mov    edx, DWORD PTR [eax]
push    edx
call    ??$some@U?$call_ifn0_t@PAU_iobuf@@H@@@@YAXU?$call_ifn0_t@PAU_iobuf@@H@@@Z ; some<call_ifn0_t<_iobuf *,int> >

причём тут ecx перед call, который пушится, равен eax после возврата.

а вот отсутствие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 4
mov    DWORD PTR $T20358[ebp], eax
mov    ecx, DWORD PTR $T20358[ebp]
push    ecx
call    ??$some@U?$call_ifn0_t@PAU_iobuf@@H@@@@YAXU?$call_ifn0_t@PAU_iobuf@@H@@@Z ; some<call_ifn0_t<_iobuf *,int> >


то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.
Re[13]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 01:10
Оценка:
Здравствуйте, Piko, Вы писали:

P>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.


ещё:
int main()
{
    auto temp=call_ifn0(fclose);
    printf("");
}


rvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR _temp$[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
; Line 27
mov    esi, esp
push    OFFSET $SG19940
call    DWORD PTR __imp__printf

eax тут вообще не используется

отсутсвие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 4
mov    DWORD PTR $T20360[ebp], eax
mov    ecx, DWORD PTR $T20360[ebp]
mov    DWORD PTR _temp$[ebp], ecx
; Line 27
mov    esi, esp
push    OFFSET $SG19935
call    DWORD PTR __imp__printf


причём была бы там структура побольше, было бы наглядней:
rvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR _temp$[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
; Line 28
mov    esi, esp
push    OFFSET $SG19942
call    DWORD PTR __imp__printf


отсутствие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR $T20363[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
mov    edx, DWORD PTR [eax]
mov    DWORD PTR $T19931[ebp], edx
mov    ecx, DWORD PTR [eax+4]
mov    DWORD PTR $T19931[ebp+4], ecx
mov    edx, DWORD PTR [eax+8]
mov    DWORD PTR $T19931[ebp+8], edx
mov    ecx, DWORD PTR [eax+12]
mov    DWORD PTR $T19931[ebp+12], ecx
mov    edx, DWORD PTR [eax+16]
mov    DWORD PTR $T19931[ebp+16], edx
mov    eax, DWORD PTR [eax+20]
mov    DWORD PTR $T19931[ebp+20], eax
mov    ecx, DWORD PTR $T19931[ebp]
mov    DWORD PTR _temp$[ebp], ecx
mov    edx, DWORD PTR $T19931[ebp+4]
mov    DWORD PTR _temp$[ebp+4], edx
mov    eax, DWORD PTR $T19931[ebp+8]
mov    DWORD PTR _temp$[ebp+8], eax
mov    ecx, DWORD PTR $T19931[ebp+12]
mov    DWORD PTR _temp$[ebp+12], ecx
mov    edx, DWORD PTR $T19931[ebp+16]
mov    DWORD PTR _temp$[ebp+16], edx
mov    eax, DWORD PTR $T19931[ebp+20]
mov    DWORD PTR _temp$[ebp+20], eax
; Line 28
mov    esi, esp
push    OFFSET $SG19937
call    DWORD PTR __imp__printf
Re[13]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 01:59
Оценка:
P>при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.
P>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.

Таки получается что чутьё меня не подвело, а CL откровенно тупит. Получается что я был о нём лучшего мнения. Ну и нафиг нужен такой RVO?

#include <stdio.h>

struct A {
  void *f;
  void operator()() { printf("%p\n",f); }
};

A __declspec(noinline) g(void *p) {
  A a = { p };
  return a;
}

struct B {
  void *f;
  B(void *ff) : f(ff) {}
  void operator()() { printf("%p\n",f); }
};

B __declspec(noinline) gg(void *p) {
  return B(p);
}

int main()
 {
   A a = g((void*)1);
   B b = gg((void*)2);
   a();
   b();
 }


cl -O2 1.cpp -FAsc

; 25   :    A a = g((void*)1);
  00000    51         push     ecx

; 25   :    A a = g((void*)1);

  00001    6a 01         push     1
  00003    e8 00 00 00 00     call     ?g@@YA?AUA@@PAX@Z    ; g
  00008    8b d0         mov     edx, eax

; 26   :    B b = gg((void*)2);

  0000a    8d 44 24 04     lea     eax, DWORD PTR _b$[esp+8]
  0000e    6a 02         push     2
  00010    50         push     eax
  00011    e8 00 00 00 00     call     ?gg@@YA?AUB@@PAX@Z    ; gg

; 27   :    a();

  00016    52         push     edx
  00017    68 00 00 00 00     push     OFFSET ??_C@_03OHEJPPDF@?$CFp?6?$AA@
  0001c    e8 00 00 00 00     call     _printf

; 28   :    b();

  00021    8b 4c 24 14     mov     ecx, DWORD PTR _b$[esp+24]
  00025    51         push     ecx
  00026    68 00 00 00 00     push     OFFSET ??_C@_03OHEJPPDF@?$CFp?6?$AA@
  0002b    e8 00 00 00 00     call     _printf
Re[14]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 02:20
Оценка:
P>причём была бы там структура побольше, было бы наглядней:

а что давай сделаем побольше )))

#include <stdio.h>

struct A {
  void *f;
  void *q;
  void operator()() { printf("%p,%p\n",f,q); }
};

A __declspec(noinline) g(void *p) {
  A a = { p };
  return a;
}

struct B {
  void *f;
  void *q;
  B(void *ff) : f(ff), q(0) {}
  void operator()() { printf("%p,%p\n",f,q); }
};

B __declspec(noinline) gg(void *p) {
  return B(p);
}

int main()
 {
   A a = g((void*)1);
   B b = gg((void*)2);
   a();
   b();
 }


cl -O2 -FAs 1.cpp

?g@@YA?AUA@@PAX@Z PROC                    ; g, COMDAT
; 11   :   A a = { p };
    mov    eax, DWORD PTR _p$[esp-4]
    xor    edx, edx
; 12   :   return a;
    ret    0

?gg@@YA?AUB@@PAX@Z PROC                    ; gg, COMDAT
; 23   :   return B(p);
    mov    eax, DWORD PTR ___$ReturnUdt$[esp-4]
    mov    ecx, DWORD PTR _p$[esp-4]
    mov    DWORD PTR [eax], ecx
    mov    DWORD PTR [eax+4], 0
    ret    0

_main    PROC                        ; COMDAT
; 27   :  {
    sub    esp, 8
    push    esi
; 28   :    A a = g((void*)1);
    push    1
    call    ?g@@YA?AUA@@PAX@Z            ; g
    mov    esi, eax
; 29   :    B b = gg((void*)2);
    lea    eax, DWORD PTR _b$[esp+16]
    push    2
    push    eax
    call    ?gg@@YA?AUB@@PAX@Z            ; gg
; 30   :    a();
    push    edx
    push    esi
    push    OFFSET ??_C@_06MJPHCGKI@?$CFp?0?$CFp?6?$AA@
    call    _printf
; 31   :    b();
    mov    ecx, DWORD PTR _b$[esp+40]
    mov    edx, DWORD PTR _b$[esp+36]
    push    ecx
    push    edx
    push    OFFSET ??_C@_06MJPHCGKI@?$CFp?0?$CFp?6?$AA@
    call    _printf
    add    esp, 36                    ; 00000024H
; 32   :  }


Действительно нагляднее. Однако у студии серьёзные проблемы с пессимизацией оптимизации возвращаемого значения. Gcc этим не страдает.
Re[2]: Копирующий конструктор и копирующий operator= по умолчанию.
От: Centaur Россия  
Дата: 19.09.12 04:23
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно.

ШЕ>Об этом надо помнить.

Каноническая формулировка называется Law of the Big Three: «если в вашем классе понадобилось явно определить деструктор, копирующий конструктор или оператор присваивания, скорее всего вам нужны все три».
Re[3]: TOP граблей С++ для новичков
От: igna Россия  
Дата: 19.09.12 05:15
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>Ребята, вот зачем вот это вот всё ?

MZ>В форумах по линуксу линуксоиды сруца, какой дистр лучше.
MZ>В форумах по плюсам -- кто плюсы знает лучше ...

Чтобы узнать новое. В данном случае у топикстартера есть шанс понять, что он (пока еще) не гуру. Продолжать пописывать советы конечно можно, но рекомендовать их "собеседуемым" не стоит, тем более, что в природе существуют аналогичные советы мирового уровня.
Re[4]: Resource Acquisition Is Initialization
От: DarkTranquillity  
Дата: 19.09.12 06:23
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Abyx, Вы писали:


ШЕ>>>Для динамических объектов можно использовать смарт указатели. Например: shared_ptr (boost::shared_ptr, std::shared_ptr) или std::auto_ptr

A>>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr

I>Вот кстати пример того, почему лучше все-таки читать советы настоящих, а не доморощенных гуру.


И кто в данном случае кто?
Re[3]: TOP граблей С++ для новичков
От: wander  
Дата: 19.09.12 06:52
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ> Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать

MZ> хоть когда-нибудь?

Гнев на технологии лучше тоже не обращать. Технологии надо анализировать и оценивать и, следовательно, применять или не применять по результатам. А гневаться лучше на что-нибудь другое.
avalon 1.0rc3 build 426, zlib 1.2.3
Re[2]: forward declaration и оператор delete
От: sokel Россия  
Дата: 19.09.12 07:08
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>delete не может вызвать деструктор для тех объектов, чьё объявление классов он не видит.


ну об этом и компилятор прожужжит если что:
function 'int main(int, char**)':
warning: possible problem detected in invocation of delete operator:
warning: 'v' has incomplete type
warning: forward declaration of 'struct human_t'
note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.


ну или так:
warning C4150: deletion of pointer to incomplete type 'human_t'; no destructor called
see declaration of 'human_t'
Re[5]: Resource Acquisition Is Initialization
От: igna Россия  
Дата: 19.09.12 07:26
Оценка:
Здравствуйте, DarkTranquillity, Вы писали:

DT>И кто в данном случае кто?


Настоящие гуру это Мейерс, Саттерс и Ко.
Re[3]: Resource Acquisition Is Initialization
От: savitar  
Дата: 19.09.12 08:05
Оценка:
Здравствуйте, Abyx, Вы писали:

A>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr


Согласен, но на практике вынужден использовать std::auto_ptr из-за Boost.PointerContainer, который я обычно использую в любом проекте.
Почему то разработчики PointerContainer не удосужились сделать методы с тем же boost::scoped_ptr, поэтому приходится делать так:
boost::ptr_vector<MyClass> vec;
std::auto_ptr<MyClass> p(new MyClass);
p->doSomethingUnsafe();
vec.push_back(p);

Если бы хотябы у boost::scoped_ptr был метод release(), но его нет, интересно почему?
Re[4]: Resource Acquisition Is Initialization
От: Abyx Россия  
Дата: 19.09.12 08:36
Оценка:
Здравствуйте, savitar, Вы писали:

A>>std::auto_ptr устарел. в С++03 лучше использовать boost::scoped_ptr или boost::unique_ptr


S>Согласен, но на практике вынужден использовать std::auto_ptr из-за Boost.PointerContainer, который я обычно использую в любом проекте.

S>Если бы хотябы у boost::scoped_ptr был метод release(), но его нет, интересно почему?

есть секретный класс <boost/interprocess/smart_ptr/unique_ptr.hpp>
In Zen We Trust
Re[2]: TOP граблей С++ для новичков
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 19.09.12 09:20
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>
L_L>....
L_L>int * arr = new int[some_size];

L_L>if (laja)
L_L>   return;
L_L>...

L_L>delete [] arr;
L_L>


Почему он вектор не использует?
Sic luceat lux!
Re: Не работает
От: UA Украина  
Дата: 19.09.12 10:27
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Сейчас приходится собеседовать много новичков.

ШЕ>Заметил что ничего в жизни не меняется.
ШЕ>Даже люди с опытом работы в крупных наступают на те же грабли, на которые наступал я в своё время.

ШЕ>Хочу представить такие рекомендации новичкам в C++. Для того чтобы вы могли повысить свой уровень

ШЕ>ну и хотя бы лучше пройти собеседование.

Для новичков все эти советы не работают, пока они сами не наступят на все эти грабли.
Здесь выбор только один из двух: — не брать новичков; — смириться (если есть дополнительные деньги и время на рефакторинг и обучение)
Re[14]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 10:51
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

P>>при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.

P>>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.
AS>Таки получается что чутьё меня не подвело, а CL откровенно тупит. Получается что я был о нём лучшего мнения. Ну и нафиг нужен такой RVO?

а знаешь что ему голову сносит? Аггрегаты!
#include <stdio.h>
#include <algorithm>

struct Constructor
{
    void *f;
    char c[20];
    Constructor(void *ff) : f(ff) { std::fill(c,c+20,0xCC); }
    void operator()() { printf("%p\n",f); }
};

Constructor __declspec(noinline) constructor(void *p)
{
    Constructor a ( p );
    return a;
}

struct Aggregate
{
    void *f;
    char c[20];
    void operator()() { printf("%p\n",f); }
};

Aggregate __declspec(noinline) aggregate(void *p)
{
    Aggregate a ={ p };
    return a;
}

int main()
{
    Constructor a = constructor((void*)1);
    Aggregate b = aggregate((void*)2);
    a();
    b();
}

cl -O2 1.cpp -FAsc
; 34   :     Constructor a = constructor((void*)1);

lea    eax, DWORD PTR _a$[esp+80]
push    1
push    eax
call    ?constructor@@YA?AUConstructor@@PAX@Z    ; constructor

; 35   :     Aggregate b = aggregate((void*)2);

lea    ecx, DWORD PTR $T20890[esp+88]
push    2
push    ecx
call    ?aggregate@@YA?AUAggregate@@PAX@Z    ; aggregate
mov    edx, DWORD PTR [eax+4]
mov    ecx, DWORD PTR [eax+8]
mov    esi, DWORD PTR [eax]
mov    DWORD PTR _b$[esp+100], edx
mov    edx, DWORD PTR [eax+12]
mov    DWORD PTR _b$[esp+104], ecx
mov    ecx, DWORD PTR [eax+16]
mov    DWORD PTR _b$[esp+108], edx
mov    edx, DWORD PTR [eax+20]
Re[3]: TOP граблей С++ для новичков
От: Lorenzo_LAMAS  
Дата: 19.09.12 12:07
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Здравствуйте, Lorenzo_LAMAS, Вы писали:


L_L>>соседушко по офису, дебил и неряха, десятилетиями пишет код вида:

L_L>>Спасает только статический анализатор, который заваливает этого ЛОШАРУ горами сообщений.
L_L>>Ес-но, фикся, кретин плодит новое говно и получает по тупой харе от анализатора и т.д. — имя этому процессу — бесконечность.

CC>А куда смотрит тимлид и прочий менеджмент?


видимо, пофигу. то ли тут действует правило: "чел старый и проверенный" (он у истоков), то ли еще проще: ковыряться в высерах этого "творца" никому не охота, пусть он сам и сидит годами на этом дерьме.
Of course, the code must be complete enough to compile and link.
Re[4]: TOP граблей С++ для новичков
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 19.09.12 12:54
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

K>>Почему он вектор не использует?


L_L>это был мой первый вопрос, когда я смотрел его код лет 7 назад. теперь мне очень стыдно, что я это спросил, я

L_L>переоценил чувака.
Да вообще всякое бывает. Может такое было оправдано? Хотя в 99% проще заюзать стл.

L_L>кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин,

Странно, что был выбран вектор для этого.
L_L>он быстро сообразил мозгом макаки, что написать это с галимым ручным управлением памятью ему уже БАНАЛЬНО НЕ ПОД СИЛУ.
L_L>в итоге все кончилось сломанным билдом не некоторых платформах — про включение заголовка и про пространства имен козел не сообразил.
Зато он наверное все собеседования прошёл.
Sic luceat lux!
Re[5]: TOP граблей С++ для новичков
От: Piko  
Дата: 19.09.12 13:34
Оценка:
Здравствуйте, Kernan, Вы писали:

L_L>>кстати, в этом году он все-таки решил использовать вектор — ГАГАГА, ему был нужен динамически растущий массив и, блин,

K>Странно, что был выбран вектор для этого.

а что не так? vector — он как-бы дефолт, и не плохой дефолт. и даже в стандарте написанно, что он дефолт.
хочется deque? нужно сначала обосновать
Re[15]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 14:40
Оценка:
P>а знаешь что ему голову сносит? Аггрегаты!

Я вот чего понять не могу, ты прикалываешься или серьёзно не знаешь что на x86 C/C++ оптимально возвращают объекты размером до 2 слов процессора через регистры? Очевидно, что студия откровенно тупит, не оптимизируя такой кейc с RVO. Ещё более она тупит при возврате структуры размером больше двух слов, чего гнусь не делает. Что меня удивило, да. Гнусь возвращает такие структуры совершенно одинаково для обоих случаев.

То есть мой способ, там где он использован, заведомо не хуже чем любой другой. Так что не надо придумывать новую задачу и говорить что в ней то всё не так. Это уже будет другая задача.
Re[16]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 14:54
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

P>>а знаешь что ему голову сносит? Аггрегаты!

AS>Я вот чего понять не могу, ты прикалываешься или серьёзно не знаешь что на x86 C/C++ оптимально возвращают объекты размером до 2 слов процессора через регистры?

ээ, я пример привёл — там точно больше двух слов

AS>Очевидно, что студия откровенно тупит, не оптимизируя такой кейc с RVO.


там NRVO.
RVO она даже в debug делает

AS>То есть мой способ, там где он использован, заведомо не хуже чем любой другой. Так что не надо придумывать новую задачу и говорить что в ней то всё не так. Это уже будет другая задача.


да не, естественно в том примере это вообще не важно, точно также как shared_ptr — это обсудили вроде?
я в общем показываю, что RVO предпочтительней...
Re[17]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 15:09
Оценка:
P>я в общем показываю, что RVO предпочтительней...

Зависит, как бы.
Re[6]: Resource Acquisition Is Initialization
От: Кодт Россия  
Дата: 19.09.12 18:39
Оценка:
Здравствуйте, igna, Вы писали:

I>Настоящие гуру это Мейерс, Саттерс и Ко.


Саттерс — это семья Саттеров? Уже молчу, кто такой гуру всех времён и народов К.О. (хотя... если взглянуть на мой никнейм...)

Кстати, напоминаю о существовании правил форума, где попрекание собеседников нехваткой квалификации не приветствуется.
Перекуём баги на фичи!
Re: TOP граблей С++ для новичков
От: kov_serg Россия  
Дата: 20.09.12 12:29
Оценка:
Деструкторы записывают обратно свою таблицу виртуальных функций.
#include <stdio.h>

struct A {
  void check_fn() { printf("check:"); fn(); }
  virtual void fn() { printf("A.fn\n"); }
  virtual ~A() { printf("~A\n"); check_fn(); }
};

struct B : A {
  void fn() { printf("B.fn\n"); }
  ~B() { printf("~B\n"); }
};

int main(int,char**) {
  B b;
  b.check_fn();
  return 0;
}
Output:
check:B.fn
~B
~A
check:A.fn

Типичная грабля с использованием этого факта
struct Thread { // TThread, CWinThread...
  virtual void Run()=0;
  virtual ~Thread() { Join(); }
  void Join() { ... }
  void Start() { ... }
};
struct MsgThread : Thread {
  void Run() { 
    for(;;) dispatch_message();
  }
  virtual void dispatch_message() {...}
};
...
void test() {
  MsgThread t;
  t.Start();
  sleep(100);
  // тут неявный вызов ~MyThread, он в свою очередь запустит ~Thread который начнёт ожидать завершения потока.
  // и почти сразу упадёт Run т.к. указателя на dispatch_message уже нет. ~Thread поменял vft.
}

Настипить можно в C++Builder и VisualStudio c MFC
Re[2]: TOP граблей С++ для новичков
От: XuMuK Россия  
Дата: 21.09.12 07:25
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Деструкторы записывают обратно свою таблицу виртуальных функций.


не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные, самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).
Re[3]: TOP граблей С++ для новичков
От: kov_serg Россия  
Дата: 21.09.12 08:40
Оценка:
Здравствуйте, XuMuK, Вы писали:

XMK>Здравствуйте, kov_serg, Вы писали:


_>>Деструкторы записывают обратно свою таблицу виртуальных функций.


XMK>не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные, самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).

Ептить. Я же не говорю что это правильно. Я говорю что это неявная грабля на которую можно наступить. И она заложена в дизайне VCL и MFC.
Re[3]: TOP граблей С++ для новичков
От: Masterkent  
Дата: 21.09.12 09:24
Оценка:
XuMuK:

XMK>вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные


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

#include <iostream>

struct B
{
    virtual void f() { std::cout << "B::f\n"; }
    void g() { f(); }
};

struct D1 : B
{
    D1()
    {
        B *b = this;
        b->f(); // calls D1::f
        g();    // calls D1::f
    }
    virtual void f() { std::cout << "D1::f\n"; }
};

struct D2 : D1
{
    virtual void f() { std::cout << "D2::f\n"; }
};

int main()
{
    D2 d;
}
Re[4]: TOP граблей С++ для новичков
От: kov_serg Россия  
Дата: 21.09.12 15:18
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>XuMuK:


XMK>>вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные


M>Вызовы там виртуальные, только final overriders определяются специфически.


M>
#include <iostream>

M>struct B
M>{
M>    virtual void f() { std::cout << "B::f\n"; }
M>    void g() { f(); }
M>};

M>struct D1 : B
M>{
M>    D1()
M>    {
M>        B *b = this;
        b->>f(); // calls D1::f
M>        g();    // calls D1::f
M>    }
M>    virtual void f() { std::cout << "D1::f\n"; }
M>};

M>struct D2 : D1
M>{
M>    virtual void f() { std::cout << "D2::f\n"; }
M>};

M>int main()
M>{
M>    D2 d;
M>}


Не понял о чем вы спроите
class CLASS {
 ctor {
  this->vft=CLASS.vft;
  ctor_body();
 }
 dtor {
  this->vft=CLASS.vft;
  dtor_body();
 }
}

В конструкторе всегда таблица от текущего класса и в деструкторе тоже.
Именно эта особенность приводит к граблям при параллельном исполнении.
Re[3]: TOP граблей С++ для новичков
От: Кодт Россия  
Дата: 21.09.12 20:50
Оценка:
Здравствуйте, XuMuK, Вы писали:

_>>Деструкторы записывают обратно свою таблицу виртуальных функций.


XMK>не важно кто что и куда записывает, вирутальные функции вызванные из конструктора или деструктора вызываются как невиртуальные,


Функции там вызываются как виртуальные — но только для текущего типа, т.е. для базы.
Насколько компилятору хватает поля зрения, он подменяет виртуальный вызов статическим.
struct base
{
  virtual void f() {}
  void g() { f(); } // здесь будет заведомо виртуальный вызов (хотя, компилятор может проинлайнить g()...)
  base() { f(); g(); } // по крайней мере единожды будет виртуальный вызов f() - из g()
};


XMK> самый простой способ не наступать на грабли: "не делайте так" (используйте двухфазную инициализацию/удаление).


"Не делайте так" здесь значит более общее: не лезьте в разрушаемый объект, особенно — из другого потока, особенно — оставаясь в функции-члене разрушаемого объекта (впрочем, есть способ отстрелить себе ногу и в однопоточном режиме и даже без виртуальных функций).
struct foo
{
  std::string name;

  void curricumvita()
  {
    born();
    lived();
    dead();
    rip();
  }

  void born()  { name = "foo"; }
  void lived() { std::cout << "hello, " << name << std::endl; }
  void dead()  { delete this; }
  void rip()   { std::cout << "R.I.P. " << name << std::endl; } // бабах!
};

int main() { new foo(); }


А рецепт с двухфазностью — да, рулит. В том числе и здесь.
Перекуём баги на фичи!
Re[4]: TOP граблей С++ для новичков
От: kov_serg Россия  
Дата: 21.09.12 21:32
Оценка:
Здравствуйте, Кодт, Вы писали:
...
К>А рецепт с двухфазностью — да, рулит. В том числе и здесь.
Рулить то оно может и рулит, но:
http://docwiki.embarcadero.com/Libraries/en/System.Classes.TThread.Execute
http://msdn.microsoft.com/en-us/library/48xz4yz9(v=vs.110).aspx

Не всплывёт его бедное тело, грабли на дне я поставил умело.

Re[5]: TOP граблей С++ для новичков
От: Кодт Россия  
Дата: 22.09.12 07:46
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>

Не всплывёт его бедное тело, грабли на дне я поставил умело.

Антипаттерн "самоубийца" зашит в библиотеку C'est la vie. (Et la MORT!!!)
Имхо, лучшее, что можно сделать здесь — это использовать TThread/CWinThread исключительно как хэндл потока, и никогда от них не наследоваться.
Не приходит же в голову (или приходит? после стольких лет с дебилдером и мфц?) наследоваться от boost/std::thread ?
Перекуём баги на фичи!
Re: TOP граблей С++ для новичков
От: carpenter СССР  
Дата: 23.09.12 18:12
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

вставка и , особенно, удаление из stl контейнеров ... в частности вектора

... код приводить не буду, ибо нефик
Re[3]: delete и delete[] различаются
От: carpenter СССР  
Дата: 24.09.12 16:27
Оценка:
Здравствуйте, carpenter, Вы писали:

интересна аргументация минуса
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.