За/против:Инициализация переменной в условном операторе

StackOverflow https://stackoverflow.com/questions/136548

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

Другие советы

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

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

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

if (CThing* pThing = GetThing())

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

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

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

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

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

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

cout << i << endl;

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

Может ли кто-нибудь из VS проверить и посмотреть, действительно ли это все еще?

Это следуетне работает на C ++ с тех пор какдаже несмотря на то, что он поддерживает оценка короткого замыкания. Может бытьНе пытайтесь выполнить следующее:

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

эр..видишь Ответ Уэсли Тарла

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

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

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

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

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

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

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

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

if (CThing thing {})
{
}

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

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

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

{
  CThing thing {};
  if (thing.is_good())
  {
  }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top