Подтвердить что ты не робот

Pro/con: инициализация переменной в условном выражении

В С++ вы можете инициализировать переменную в выражении if, например:

if (CThing* pThing = GetThing())
{
}

Почему можно считать этот плохой или хороший стиль? Каковы преимущества и недостатки?

Лично мне нравится этот стиль, потому что он ограничивает область действия переменной pThing, поэтому ее никогда нельзя использовать случайно, когда она равна NULL. Однако мне не нравится, что вы не можете этого сделать:

if (CThing* pThing = GetThing() && pThing->IsReallySomeThing())
{
}

Если есть способ сделать вышеуказанную работу, отправьте сообщение. Но если это просто невозможно, мне все равно хотелось бы знать, почему.

Вопрос, заимствованный отсюда, похожая тема, но PHP.

4b9b3361

Ответ 1

Важно то, что объявление в С++ не является выражением.

bool a = (CThing* pThing = GetThing()); // not legit!!

Вы не можете выполнять как декларацию, так и логическую логику в выражении if, спецификация языка С++ специально позволяет либо выражение, либо объявление.

if(A *a = new A)
{
    // this is legit and a is scoped here
}

Как узнать, определено ли в одном выражении между одним термином и другим?

if((A *a = new A) && a->test())
{
    // was a really declared before a->test?
}

Укусите пулю и используйте внутренний if. Правила области полезны, и ваша логика ясна:

if (CThing* pThing = GetThing())
{
    if(pThing->IsReallySomeThing())
    {
    }
}

Ответ 2

О преимуществах:

Всегда рекомендуется определять переменные, когда они вам сначала нужны, а не строка раньше. Это улучшает читабельность вашего кода, так как можно сказать, что CThing не имеет прокрутки и поиска там, где он был определен.

Также, уменьшая область действия до цикла /if, эта переменная приводит к тому, что переменная не отображается после выполнения кода, что делает ее кандидатом на сборку мусора (если язык поддерживает эту функцию).

Ответ 3

if (CThing* pThing = GetThing())

Это плохой стиль, потому что внутри if вы не предоставляете логическое выражение. Вы предоставляете CThing*.

CThing* pThing = GetThing();
if (pThing != NULL)

Это хороший стиль.

Ответ 5

Одна из причин, по которой я обычно не делаю этого, объясняется общей ошибкой пропущенного "=" в условном тесте. Я использую lint с установленными ошибками/предупреждениями, чтобы их поймать. Затем он будет кричать о всех назначениях внутри условных выражений.

Ответ 6

Просто FYI некоторые из старых компиляторов Microsoft С++ (Visual Studios 6 и .NET 2003, я думаю) не совсем следуют правилу определения области видимости в некоторых случаях.

for(int i = 0; i > 20; i++) {
     // some code
}

cout << i << endl;

Я должен быть вне сферы действия, но это был/действительный код. Я считаю, что это было сыграно как функция, но, на мой взгляд, это просто несоблюдение. Не придерживаться стандартов плохо. Также как веб-разработчик об IE и Firefox.

Может ли кто-нибудь с VS проверить и убедиться, что это все еще актуально?

Ответ 7

Так много вещей. Прежде всего, голые указатели. Пожалуйста, избегайте их всеми средствами. Используйте ссылки, необязательно, unique_ptr, shared_ptr. В качестве последнего средства напишите свой собственный класс, который занимается владением указателем и ничем иным.

Используйте унифицированную инициализацию, если вам может потребоваться С++ 11 (С++ 14 предпочтительнее, чтобы избежать дефектов С++ 11): - он позволяет избежать путаницы = vs == и более строг при проверке аргументов, если таковые имеются.

if (CThing thing {})
{
}

Убедитесь, что реализовали operator bool, чтобы получить предсказуемое преобразование из CThing в bool. Однако имейте в виду, что другие люди, читающие код, не увидят operator bool сразу. Явные вызовы методов обычно более читабельны и обнадеживают. Если вам может потребоваться С++ 17, используйте синтаксис инициализатора.

if (CThing thing {}; thing.is_good())
{
}

Если С++ 17 не вариант, используйте объявление выше, если другие предложили.

{
  CThing thing {};
  if (thing.is_good())
  {
  }
}

Ответ 8

Вы можете иметь операторы инициализации внутри if и switch, начиная с С++ 17.

Ваш код теперь будет:

if (CThing* pThing = GetThing(); pThing->IsReallySomeThing())
{
    // use pThing here
}
// pThing is out of scope here

Ответ 9

Вы также можете заключить задание в дополнительный набор(), чтобы предотвратить предупреждение.

Ответ 10

Я вижу это как опасное. Следующий код намного безопаснее, а прилагаемые фигурные скобки по-прежнему ограничивают область pThing так, как вы хотите.

Я предполагаю, что GetThing() иногда возвращает NULL, поэтому я помещаю это смешное предложение в оператор if(). Это предотвращает вызов IsReallySomething() с помощью указателя NULL.

{
    CThing *pThing = GetThing();
    if(pThing ? pThing->IsReallySomeThing() : false)
    {
    // Do whatever
    }
}

Ответ 11

также заметим, что если вы пишете код на С++, вы должны сделать предупреждение компилятора о "=" в условном выражении (которое не является частью объявления) ошибкой.

Ответ 12

Это приемлемая и хорошая практика кодирования. Тем не менее, люди, которые не исходят из низкоуровневого кода, вероятно, не согласятся.