Сионист писал(а):
А если...
Альтернатива - декларировать в заголовке цикла то, что имеет смысл во всей функции, так как в ней записан только линейно-циклический алгоритм многократного перебора контейнера по сути одним и тем же итератором, со вставкой из поиска и модификации по сути по тому же самому итератору, а это приведёт к лишему дублированию декларации, да ещё и появится двухстрочный блок на пустом месте. Вторая альтернатива - пустая первая позиция в заголовке цикла, что хорошо лишь в случае, когда один цикл продолжает перебор изменяемой в цикле переменной, уже перебранной в предыдущем цикле, а здесь этого нет.
Или? Декларация между операциями конечно читается, но со спотыканием и слишком рано инициировать конкретным значением тоже плохо. Потому и присваивание вместо инициализации. А если итератор - это вообще out-параметр функции, но не in-параметр? Например...
Много белого шума... Причём бесполезного, так как на следующей же строчке я написал, что согласен, что для других случаев дефолтный конструктор понадобится. Ты что, прочёл первую строку, весь исполнился праведного гнева, накатал три страницы текста, а следующую строку прочитал только после того, как иссяк, и, посмотрев на то, сколько работы проделано, решил не удалять результаты аврального труда?
Сионист писал(а):
Код: Выделить всё
void Extrems(TList List; TList::Iterator &Min, TList::Iterator &Max)
А вот за это нужно бить, причём нещадно. List - только константной ссылкой и никак иначе! Копирование тяжёлых объектов при передаче параметров - это один из признаков "дурно пахнущего кода".
Сионист писал(а):Потому что так удобнее
Удобнее, чем что? Чем в списке инициализации указать? Вместо "равно" написать скобочки, и уже не удобно сразу? Очень спорное утверждение... Неудобно спать на потолке, а код нужно писать не так, чтобы он был удобным, а так, чтобы был правильным.
Сионист писал(а):... и ни чего не мешает так делать.
Как раз мешает. Во всяком случае должно мешать хорошему программисту. Спросишь что? Отвечу - здравый смысл. Если тебе ничего не мешает, то делай выводы сам...
Инициализация вызывается в любом случае. Если ты её не прописываешь явно, то для поля вызывается дефолтный конструктор. Зачем вызывать дефолтный конструктор и затем вызывать оператор присваивания, если можно сразу проинициализировать поле нужным значением? Если поле - объект тяжёлого класса, то разница в скорости выполнения может быть существенной. Скажешь, что для встроенных типов, таких, как указатели, профит будет мизерным? Да соглашусь. Но зачем отказываться от мизерного профита, если его можно добиться совсем не тратя сил? А ведь есть ещё один аргумент. Есть типы, которые можно только инициализировать, а присваивать нельзя. Это константы. Именно поэтому у тебя с константным Owner не будет работать код конструктора в текущем его состоянии, но будет работать, если переписать на инициализацию.
Совет на будущее. Всегда используй инициализацию везде, где это возможно. Присваивание используй лишь тогда, когда это действительно необходимо по контексту (когда переменная должна хранить сначала одно значение, а потом другое). Такой подход - это признак хорошего тона в С++.
Сионист писал(а):
Инициализация в конструкторе повторяет сие синтаксис явного вызова конструктора предка. А часто ли он вообще используется? Даже в сумме для инициализации полей и для передачи части параметров конструктора конструктору предка его класса? А присваивание часто. Частое применение даёт меньше шансов переврать синтакис, к тому же синтаксис присваивания проще.
Чистый бред. Читается так, будто писал человек, который вообще начал программировать на С++ два дня назад. Избавляйся уже от заблуждений молодости, пора становиться более зрелым программистом...
Сионист писал(а):Что за поле? Как кодировать в нём инфу о месте и характере ошибки? Как бросать? Как выводить в лог при перехвате?
Вот пример:
Код: Выделить всё
class List
{
...
class Exception
{
public:
enum class Type : int { Deref, Common };
Exception(Type type) : m_type(type) {}
std::string GetDescription() const
{
switch (m_type)
{
case Type: :D eref:
return "Error of dereferencing";
case Type::Common:
return "Common error";
}
assert(false);
return "";
}
private:
Type m_type;
};
...
class Iterator
{
...
if (!Pointer) throw Exception(Exception::Type: :D eref);
...
};
...
};
int main()
{
List list;
List::Iterator it;
try
{
*it;
}
catch (const List::Exception& ex)
{
std::cout << ex.GetDescription() << std::endl;
return 1;
}
return 0;
}
Набор ошибок, конечно, нужно расширить.