C++/STL и memset
Кто что думает по этому поводу?Думаем, что пока такие темы будут здесь появляться, недальновидные личности будут продолжать писать, что C++ - полное гавно.
Я правильно понял, что в твоём примере источник проблем — вызов memset на уже сконструированную структуру из объекта другого класса? Если да, то нафига так делать, ясно же что для членов деструкторы не будут вызваны?
C++ - полное говно, зачем ты на нём пишешь?
Если да, то нафига так делать, ясно же что для членов деструкторы не будут вызваны?это почему? Студия вызывает.
Короче, пример.
Вася Пупкин написал класс:
class VPupkin_Class
{
int m_int;
char *m_char;
size_t m_charlen;
char m_arr[32];
public:
VPupkin_Class
{
memset(this, 0, sizeof(*this;
m_int = 3;
}
//здесь куча других функций
};
Потом он уволился, а вместо него над кодом начал работать Петя Индишный. В ходе написания новой версии, им потребовалось добавить пару полей в класс VPupkin_Class. Ему было лень писать свой класс-наследник и он просто модифицировал класс Васи:
class VPupkin_Class
{
int m_int;
char *m_char;
size_t m_charlen;
char m_arr[32];
string m_name;
wstring m_somewstring;
public:
VPupkin_Class
{
memset(this, 0, sizeof(*this;
m_int = 3;
}
//здесь куча других функций
void SetName(char* name)
{
m_name = name;
}
//.....
};
И получаем мемлики, т.к. в момент выполнения конструктора VPupkin_Class, конструкторы для m_name и m_somewstring уже вызваны.
зы: в моём случае было конечно хуже:
typedef struct {int field;wstring somestr;....} AStruct;Но подозреваю, что когда-то в AStruct строк небыло.
class SomeClass
{
...
AStruct m_struct;
...
public:
SomeClass
{
.....
memset(m_struct, 0, sizeof(AStruct;
....
}
};
class VPupkin_Class
{
int m_int;
char *m_char;
size_t m_charlen;
char m_arr[32];
public:
VPupkin_Class
{
memset(this, 0, sizeof(*this;
m_int = 3;
}
//здесь куча других функций
};
class VPupkin_Class
{
int m_int;
char *m_char;
size_t m_charlen;
char m_arr[32];
string m_name;
wstring m_somewstring;
public:
VPupkin_Class
{
memset(this, 0, sizeof(*this;
m_int = 3;
}
//здесь куча других функций
void SetName(char* name)
{
m_name = name;
}
//.....
};
typedef struct {int field;wstring somestr;....} AStruct;
class SomeClass
{
...
AStruct m_struct;
...
public:
SomeClass
{
.....
memset(m_struct, 0, sizeof(AStruct;
....
}
};
Спасибо, подрочил. Говнокодьте ещё.
struct my_str {
int a;
std::string str;
};
my_str *my = (my_str *) malloc(sizeof(my_str;
создает указатель на какую-то неадекватную хрень.
memset для инициализации можно использовать только для обнуления структур, которые нужны для вызова некоторых WinAPI методов и описаны в Platform SDK. Больше для инициализации memset юзать нигде нельзя, да и не для инициализации тоже нежелательно.
Плохому танцоруююю
struct tagmyStruct{
tagmyStruct : a(0b(0c(0d(0str("string") {};
int a;
int b;
size_t c;
unsigned char *d;
std::string str;
};
кстати очень странно, что ты лик получил, а не сегфолт, обнуляя все что не попадя мемсетом
вот тебе еще один пример, хоть и не по теме
class Base {
public:
virtual void p {
}
};
class Derived : public Base {
public:
void p {
}
};
int main
{
Derived * p = new Derived;
memset(p,0,sizeof(Derived;
p->p;
}
Если очень хочется memset, то можно применить его для структур с элементарными полями, а более сложные поля (типа stl-ных и других с конструкторами) добавлять в производный класс. Их конструкторы тогда будут вызваны после мемсета простых полей (который останется в базовом). Но это требует дисциплины, как впрочем и первый вариант..
memset для инициализации можно использовать только для обнуления структур, которые нужны для вызова некоторых WinAPI методовТак то ведь C, а не C++.
по хорошему memset можно использовать только для pod типов, а все остальное от лукавого.
имхо , использовать memset для инициализации POD-типа (Plain Old Data - ботай , что это такое вполне нормално,
в конструкторе этого пода или извне
Если добавляется член - не встроенный тип (например std::string то тип перестает быть подом и инициализация memset'ом становится undefined behavior (при дальнейшем использовании этого объекта, в т.ч. удалении).
Если некий чувак добавляет новый член к типу и не удосуживается посмотреть-поправить конструкторы этого типа - этому чуваку можно только посоветовать никогда не программировать на С++.
Вообще с этим подами может случится засада, если какой-то внешний код (которой априори не просмотришь) закладывается на то, что это именно под (использует memset'ы , memcpy и прочие чисто С-приемы). В этом случае нельзя превращать под в не-под. имхо в комментах к типу должно быть написано, существенно ли то, что он под.
PS только вот я что-то я забыл, добавление конструктора к поду далает ли его не-подом? Если делает, то memset'ом пользоваться нельзя.
PPS имхо, что-то ты не то читаешь, эту Алену С++ читал по-диагонали, но она имхо не рюхает. Для начала могу посоветовать Мейерса Эффективное использование С++ (третье издание, обязательно третье там и про порядок конструирования со всеми заморочками по-моему тоже есть и с "философскими обоснованиями"
memset для инициализации можно использовать только для обнуления структур, которые нужны для вызова некоторых WinAPI методов и описаны в Platform SDK. Больше для инициализации memset юзать нигде нельзя, да и не для инициализации тоже нежелательно.Ясно. Ну примерно так я и представлял, просто перед глазами был проект, в котором memset иногда используется для инициализации структур и классов без виртуальных функций... Только вот структуры иногда сами содержали в себе объекты других классов.
PPS имхо, что-то ты не то читаешь, эту Алену С++ читал по-диагонали, но она имхо не рюхает. Для начала могу посоветовать Мейерса Эффективное использование С++ (третье издание, обязательно третье там и про порядок конструирования со всеми заморочками по-моему тоже есть и с "философскими обоснованиями"я не писал, что ботаю C++ по её постам, просто некоторые вещи подсматриваю у неё.
В общем, спасибо за детальное описание.
Если некий чувак добавляет новый член к типу и не удосуживается посмотреть-поправить конструкторы этого типа - этому чуваку можно только посоветовать никогда не программировать на С++.Этому чуваку лучше только посочувствовать и порекомендовать уволиться с поддержки такого гавна и пойти на нормальный проект. Тем более он добавляет тип, у которого есть конструктор по умолчанию, в нашей истории это std::string. Несмотря на то, что memset может работать правильно, так не пишут на C++. Ровно как и ручной захват и освобождение ресурсов: кто-то может добавить return или throw. Нельзя же сказать, что этот кто-то не умеет программировать только потому, что он заметил, что в каких-то глубинах какой-то мудак залочил мьютекс руками.
тому, кто поддерживает, имхо можно посоветовать убить того, первого чувака, дабы обезопасить себя от дальнейших перлов (ну это образно, я вообще против рукоприкладства, равно как и найма коллеров и прочее...)
да ,но если этот первый - начинающий прогер, то имхо нужно применять не драконовские меры, а скорее исправительно-воспитательные, в надежде, что он проникнется тем, какую х-ню сделал и больше так делать не будет...
Если некий чувак добавляет новый член к типу и не удосуживается посмотреть-поправить конструкторы этого типа - этому чуваку можно только посоветовать никогда не программировать на С++.вот этот шаг странный
не понятно зачем надо надо смотреть конструктор, если я добавляю в класс поле std::string.
не понятно зачем надо надо смотреть конструктор, если я добавляю в класс поле std::string.Да действительно, тебе смотреть не надо. Умные люди потом разберутся
не понятно зачем надо надо смотреть конструктор, если я добавляю в класс поле std::string.Ну если работать на проекте, над которым не работали ни индусы, ни люди, которые иногда применяют сишные приёмы в C++, то может и не нужно во всём разбираться, а в более общем случае лучше разбираться как что работает... Я бы при любом изменении поинтересовался всеми участками кода, которые могут как-либо взаимодействовать с изменением.
вот этот шаг странныйну одно из формальных объяснений - это пример как раз из этого треда
не понятно зачем надо надо смотреть конструктор, если я добавляю в класс поле std::string.
...
я сейчас подумал, если все написано в "правильном" ООП стиле, то наверное ничего от просто добавления члена сломаться не должно (опять-же, может еще есть заморочки, кроме подов, из-за которых все может сломаться, про тот же самый под, боюсь, не каждый вспомнит, когда будет правки вносить, а так - посмотрел - и сразу вспомнил , и потом через пол года не надо отлавливать утечки памяти)
а так, класс - это же не контейнер из членов, соответственно конструироваться на логическом уровне члены должны "все вместе". Даже в случае, если это инициализация простая, т.е. достаточно конструктора по умолчанию, взгянуть на конструктор и убедиться , что все ОК - не сложно. Я считаю, что это должно быть в привычке, типа той, что если ты в большой функции заводишь во вложенной области переменную, надо убедиться, что переменной с этим же именем нет во внешней области видимости (ну или типа знать точно, что на такое компилятор ругается, как в С#, если я правильно помню
взгянуть на конструктор и убедиться , что все ОК - не сложноА если его не видно?
тогда ты не сможешь и член добавить, т.к. тогда и опредления класса не должно быть видно
взгянуть на конструктор и убедиться , что все ОК - не сложно
А если его не видно?
тогда ты не сможешь и член добавить, т.к. тогда и опредления класса не должно быть видноОпределение может быть видно. В производный класс я смогу добавить что-нибудь, что умрёт из-за неправильного подхода к программированию на C++. Да и не в этом дело, если работаешь с адекватными людьми, у такой ерунде даже не думаешь. Поэтому и сам должен заботиться о правильности своего кода.
1) видеть опредление класса (в доке или выкачать с правами только для чтения или...) - это одно, а возможность внести туда изменения - это другое
2) наследование это - одно , а добавление члена - это другое
В производный класс я смогу добавить что-нибудь, что умрёт из-за неправильного подхода к программированию на C++.аааа, ну если , например, в конструктор производного добавить meset(this, 0, sizeof(... то да, конечно, че-нить интересное наверняка получится
//ZONE - некая POD-структура
class CZone : public ZONE
{
//определение дополнительных полей, методов (в т.ч. виртуальных конструктора и деструктора
};
.....
CZone zone;
memset(&zone, 0, sizeof(ZONE;
Насколько я понимаю, если где-нибудь по пути случится множественное наследование, то да, внезапно код перестанет работать.
PS. И да, FJ прав, если потом CZone будет не первым базовым классом при множественном наследовании, то аналогичный код для экземпляров того класса, конечно же, сломается.
//определение дополнительных полей, методов (в т.ч. виртуальных конструктора и деструктора
.....
memset(&zone, 0, sizeof(ZONE;
А мемсет разве не потрет указатель на таблицу виртуальных функций? Такой объект потом не стоит трогать даже палкой..
А мемсет разве не потрет указатель на таблицу виртуальных функций? Такой объект потом не стоит трогать даже палкой..ну дальнейший код вроде работает, при чём это дело компилится как студией, так и gcc, так что наверное указатель стоит после первых полей.
ну дальнейший код вроде работает, при чём это дело компилится как студией, так и gcc, так что наверное указатель стоит после первых полей.тебе заняться чтоли нечем больше. нахуя писать хуево, когда можно написать нормально.
я чего-то не понимаю, наверное.
зы: на компе у заказчика undefined behaviour *всегда* рассылает спам, портит пароли и рушит корпоративный сервер.
тебе заняться чтоли нечем больше. нахуя писать хуево, когда можно написать нормально.Часть кода, с которым мне приходится работать, писало явно не одно поколение программистов, среди которых было не мало индусов. Естественно, более новый код в основном нормальный.
я чего-то не понимаю, наверное.
по стандарту это или просто так принято, но есть куча кода, который на это расчитывает, в т.ч. и в WinAPI.Если только MFC, WINAPI - это C, там нету классов.
если в CZone есть виртуальные методы то там значит будет указатель на vtbl и memset(&zone, 0, sizeof(ZONE;-ом ты его просто затрешь (по-моему указатель на vtbl обычно в начале располагается)
расположение членов в памяти стандарт гарантирует только для подов (а все структуры в WinAPI являются подами - и это существенно)
в общем случае располежение в памяти объекта - не пода стандартом не регламентируется и остается на усмотрение компилятора. Да, обычно компиляторы располагают члены и базовые классы по порядку, но закладываться на это - это писать непортабельный код.
че-то я сейчас засомневался: если просто пронаследоваться - будет ли уже это под или нет? Признаться, я не читаю стандарт перед сном и не дрочу на изображения Страуструпа (с)
вообще у подов довольно ограниченная область применения, пихать их везде , где получается (например, из-за кажущихся удобств написания в конструкторе memset и все) - не гуд, это уже какое-то адово смешение С и С++ начинается
поды обычно используются, когда нужна бинарная совместимость между модулями, компилирующимися отдельно (пример - вызовы WinAPI)
ну ладно, соболезную тогда.
Если только MFC, WINAPI - это C, там нету классов.Да, это я потупил. Там есть структуры, которые расширяют другие структуры, при этом в памяти идёт сначала базовая структура, а потом поля расширенной. Но там таки не наследование, а тупо в расширенной структуре первый элемент - базовая структура. Хотя эффект такой же, но таки не наследование.
есть, кстати, клевый макрос offsetof, может не знает кто.
ну дальнейший код вроде работаетЭто временно.
Простой пример:
#include <windows.h>
class bomb
{
public:
int a,b;
virtual void hello
{
printf("hello\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
bomb onstack;
memset(&onstack, 0, sizeof(bomb;
onstack.hello;
bomb *onheap = new bomb;
memset(onheap, 0, sizeof(bomb;
onheap->hello;
return 0;
}
Компилял в VS2005.
Когда объект создается на стеке, вызов проходит успешно, т.к. он просто инлайнится и к таблице вирт. функций не обращается.
А вот когда в куче, идет обращение через таблицу и все падает, что и требовалось ожидать.
upd: я что-то не совсем в тему влез, что тут о под разговор
Может memset(&zone, 0, sizeof(ZONE; заменить на memset(&zone + offsetof(CZone, имя_первого_поля_в_ZONE 0, sizeof(ZONE; ?
Общий рецепт придумать нельзя, так как все сильно завязано на компилятор (реализацию наследования размещение в памяти классов ). В данном примере, первое поле в памяти может быть совсем и не первым, например, для компактности расположения.
если у супертипа нет виртуальных функций и тп, зачем от него вообще наследовать или его исправлять?
может, лучше сделать аггрегацию?
class CZone
{
public:
ZONE zone;
*****************
};
Общий рецепт придумать нельзя, так как все сильно завязано на компилятор (реализацию наследования размещение в памяти классов ). В данном примере, первое поле в памяти может быть совсем и не первым, например, для компактности расположения.Я уже об этом думал. Можно взять любое поле и использовать код вида:
memset(&zone + offsetof(CZone, имя_поля_в_ZONE) - offsetof(ZONE, имя_поля_в_ZONE 0, sizeof(ZONE;
почему бы, в случае наследования, не сделать приведение типов, а потом memset?
CZone c_zone;
ZONE* zone = &c_zone;
memset( zone, 0, sizeof( zone;
Можно взять любое поле и использовать код вида:А ещё можно не страдать хернёй, убрать memset и написать нормальный C++ конструктор.
почему бы, в случае наследования, не сделать приведение типов, а потом memset?Потому что от приведения типов адрес не меняется.
Потому что от приведения типов адрес не меняется.быстро сотри свой пост, пока никто не видел)
а как же множественное наследование?..
Потому что от приведения типов адрес не меняется.во-первых, только что проверил, что при множественном наследовании меняется адрес при приведении:
вот код (под gcc)
#include <stdio.h>
#include <string.h>
class ZONE
{
public:
ZONE { }
int a;
};
class ZONE1
{
public:
ZONE1 { }
int a;
};
class CZone : public ZONE, public ZONE1
{
public:
virtual void f { printf( "f\n"); return; }
};
int
main( )
{
CZone *c_zone = new CZone;
c_zone->f;
ZONE *zone = c_zone;
ZONE1 *zone1 = c_zone;
memset( zone, 0, sizeof(ZONE) + 1);
printf("aa\n");
c_zone->f;
printf( "%x\n", c_zone);
printf( "%x zone\n", zone);
printf( "%x zone1\n", zone1);
return 0;
}
во-вторых, если убрать упоминания о ZONE1, то будет ломаться, поскольку судя по всему, виртуальная таблица садится сразу после под-структур, а у нас стоит +1.
если убрать +1 из memset - то всё ок
Потому что от приведения типов адрес не меняется.вообще-то меняется, да еще как, особенно в случаи множественного наследования.
вообще-то меняется, да еще как, особенно в случаи множественного наследования.Согласен, я не подумал про множественное наследование, потому что писал про конкретный случай CZone : ZONE.
во-первых, только что проверил, что при множественном наследовании меняется адрес при приведении:У тебя там нету множественного наследования. Я всё-таки отвечал на твой пост.
У тебя там нету множественного наследования. Я всё-таки отвечал на твой пост.прочитай ещё раз мой вопрос, свой ответ и ответ, который я тебе написал.
я не спрашивал, будет ли меняться указатель, но то, что при приведении он может меняться - это факт.
то, что при приведении в нашем случае ты можешь не париться о виртуальной таблице, где бы та ни была - это факт тоже.
я не спрашивал, будет ли меняться указатель, но то, что при приведении он может меняться - это факт.Что при приведении он может меняться мы уже выяснили. Кстати, что-то никто не отметил мою очевидную ошибку, что при приведении к POD он тоже может поменяться. Все написали про множественное наследование, о котором в постах не упоминалось.
то, что при приведении в нашем случае ты можешь не париться о виртуальной таблице, где бы та ни была - это факт тоже.
Что при приведении в нашем случае мы можем о чём-то не заботиться - это не факт. Факт, что когда на работу выйдет нормальный программист, он несколько раз убьёт автотесты, пока не поймёт, какие мудаки с ним работают.
Что при приведении он может меняться мы уже выяснили. Кстати, что-то никто не отметил мою очевидную ошибку, что при приведении к POD он тоже меняется. Все написали про множественное наследование, о котором в постах не упоминалось.множественное наследование это хороший пример того, что затачиваться на то, где находится базовый класс, нельзя.
множественное наследование это хороший пример того, что затачиваться на то, где находится базовый класс, нельзя.Ну тогда сам ответь на свой вопрос:
почему бы, в случае наследования, не сделать приведение типов, а потом memset?Я уже ответил, просто фраза была построена неправильно - как обобщающее заявление. Я сказал, что ошибся. Тем не менее мой ответ остаётся правильным: если адрес не поменяется, то можно убить рабочий код. Тем более, что ситуация поменялся адрес или не поменялся может меняться при написании кода.
Что при приведении в нашем случае мы можем о чём-то не заботиться - это не факт. Факт, что когда на работу выйдет нормальный программист, он несколько раз убьёт автотесты, пока не поймёт, какие мудаки с ним работают.нормальный программист привык всё приводить через (void *) ?
то, что вообще ситуация с memset не очень красивая, я согласен. но я отвечал на вопрос.
нормальный программист привык всё приводить через (void *) ?Нет. Скорее, он не привык к тому, что надо следить за тем, чтобы унаследованный POD оставался POD-ом. Вообще говоря, ситуация наследования от POD и добавление виртуальных методов может в некоторых случаях быть опасной даже без memset.
то, что вообще ситуация с memset не очень красивая, я согласен. но я отвечал на вопрос.Ты не отвечал, ты его задал.
Я уже ответил, просто фраза была построена неправильно - как обобщающее заявление. Я сказал, что ошибся. Тем не менее мой ответ остаётся правильным: если адрес не поменяется, то можно убить рабочий код. Тем более, что ситуация поменялся адрес или не поменялся может меняться при написании кода.блин, виртуальной таблицы у класса ZONE нет. потому если мы его затрём нулями при инициализации, то ничего не убьём.
где же виртуальная таблица с CZone? а меня уже это не интересует - поскольку я правильно сделал приведение типов.
хватит ругаться.
чтобы унаследованный POD оставался POD-омоб этом я и написал с самого начала. наследование ради того, чтобы засунуть одну структуру в другую - это не совсем правильная вещь
блин, виртуальной таблицы у класса ZONE нет. потому если мы его затрём нулями при инициализации, то ничего не убьём.В твоём конкретном примере всё будет работать, с этим никто не спорит. Всё дело в том, что компилятор нам ничего не гарантирует в данном случае. Я просто написал, что во время разработки эта ситуация может поменяться. Да и тема, которую мы обсуждаем, стоит или не стоит пользоваться memset для инициализации в C++. Поэтому все посты рассматриваются более-менее в этом свете.
где же виртуальная таблица с CZone? а меня уже это не интересует - поскольку я правильно сделал приведение типов.
Тем не менее мой ответ остаётся правильным: если адрес не поменяется, то можно убить рабочий код.как раз таки ты ответил неверно. где адрес, нас не интересует. вопрос в том, остался ли класс ZONE подом. если вдруг кто-то в него всунул указатель на какую-то виртуальную таблицу, тогда будем ломаться.
как раз таки ты ответил неверно. где адрес, нас не интересует. вопрос в том, остался ли класс ZONE подом. если вдруг кто-то в него всунул указатель на какую-то виртуальную таблицу, тогда будем ломаться.Я писал про адрес каста - меняется он или нет, неважно по какой причине: кроссплатформенная компиляция, рефакторинг, и т.п. Выше я уже отметил, что при касте к POD адрес меняется. И написал, что ситуация может измениться во время разработки.
Вопрос - на хрена вообще забивать все нулями? Чтобы думать, что все int'ы, size_t'ы и прочие равны нулю после создания объекта? Если ты забьешь int нулями, совсем не факт, что его логическое значение будет нулем, потому что возможны платформы, на которых логический ноль у int состоит не из всех нулевых бит.
P.S. Блин, из-за тебя сейчас сижу и думаю - как переслать double число с одного компа на другой, если у них double по-разному представляется? Не в строку же конвертить...
Блин, из-за тебя сейчас сижу и думаю - как переслать double число с одного компа на другой, если у них double по-разному представляется? Не в строку же конвертить...а на каких архитектурах 8-байтный double по разному кодируется?
Вопрос - на хрена вообще забивать все нулями? Чтобы думать, что все int'ы, size_t'ы и прочие равны нулю после создания объекта? Если ты забьешь int нулями, совсем не факт, что его логическое значение будет нулем, потому что возможны платформы, на которых логический ноль у int состоит не из всех нулевых бит.Это я напиздел, конечно, int'ы, пожалуй, без проблем можно забивать нулями, т.к. memset сама принимает int. А вот забивать вещественные числа мб и не стоит. Но вообще тоже вопрос, в memset передается int, который там конвертится в char, которым уже и забивается память.
а на каких архитектурах 8-байтный double по разному кодируется?А я без понятия. Но мне никто не говорил до этого, что он кодируется везде одинаково.
Если ты забьешь int нулями, совсем не факт, что его логическое значение будет нулемЧувак, ну ты и отжигаешь
Я даже сначала подумал, что ты продолжаешь предыдущий трешак.
Я вот недавно узнал , что double можно физически забивать нулями (memset, например) и IEEE-... гарантируют, что это будет представлять 0.
имхо на практике, проблемы могут возникнуть только если на твоих платформах endian'ы не совпатают.
Чувак, ну ты и отжигаешьЯ даже сначала подумал, что ты продолжаешь предыдущий трешак.Я же подумал, и исправился =)
По поводу double я не знал, что IEEE это гарантирует, но когда-то давно читал, что так делать может быть не переносимо.
Оставить комментарий
Andbar
Преамбула.Искал причину довольно странного мемлика. Память выделялась где-то в глубине stl-я при вызове wstring::operator+=, но затем указатель затирался. Отправил данную информацию к владельцу текущего модуля, тот за выходные локализировал причину: структура, в которую входило несколько строк, инициализировалась строчкой вида "memset(&m_mystruc, 0, sizeof(m_mystruc;" в конструкторе класса-владельца структуры. Вот и получалось, что внутренние данные сконструированных строк разрушались. После этого запустил поиск по всем исходникам проекта слова memset и просматриваю каждое вхождение (в особенности вхождения типа "class SomeClass{SomeClass{memset(this, 0, sizeof(*this};...};", которых нашлось не мало). Самое интересное, что подобная гадость находится.
А вот теперь собственно вопрос.
Является ли частое использование memset (в особенности для инициализации данных объекта/структуры) признаком плохого стиля или же невозможность использовать memset на STL-ных строках являются недостатком реализации библиотеки (используемой в студии)?
С одной стороны, очень удобно писать так:
Так как при добавлении полей не нужно будет думать о их инициализации. Но с другой стороны, если мы добавляем туда wstring someStr; или другое подобное поле со своим конструктором, мы рискуем нарваться на мемлики или другие ошибки... С другой стороны, зануление области памяти по частям удлиняет код, так что имеет смысл хотя-бы часть полей занулить через memset (во всяком случае, если структура или класс часто создаётся).
Кто что думает по этому поводу?
зы: заранее прошу прощения если тема уже поднималась: пишу на C++ только с прошлого года, а до того соответствующие темы почти не читал.