Объявление и инициализация переменной в операторе Conditional или Control в C++

Test x = Test(1);

Это создает новый объект со значением «1».

x = Test(2);

Сначала создается новый объект со значением «2», после чего он будет присвоен первому объекту с оператором присваивания, который неявно создан для вашего класса! В этот момент у вас есть два объекта, каждый из которых имеет значение 2!

Чтобы получить лучшее представление, вы можете сделать это:

class Test{
    public:
        static int instanceCount;
        int id;
        int count;

        explicit Test(int id) : id{id}, count{instanceCount++} {
            std::cout << "Created " << id << " " << count << std::endl;
        }

        ~Test() {
            std::cout << "Destroyed " << id << " " << count << std::endl;
        }

        //Test& operator=(const Test&) = delete;
        Test& operator=(const Test& ex) 
        {
            id=ex.id;
            return *this;
        }
};  


int Test::instanceCount = 0;

int main() {
    Test x = Test{1};
    x = Test{2};

    std::cout << x.id << std::endl; 
    return 0;
}  

Теперь вы можете видеть, когда новый экземпляр создано. Если вы удалите оператор присваивания для своего класса, вы увидите, что первая написанная вами инструкция «Test x = Test {1};» это не задание, а конструкция. Второй "x = Test {2};" потерпит неудачу, так как вы удалили оператора сейчас.

Вывод выглядит следующим образом:

Created 1 0
Created 2 1
Destroyed 2 1
2
Destroyed 2 0

Как видите, вы получаете первый экземпляр с счетчиком 0 и вашим значением 1. Второй временный экземпляр создается как счетчик 1 с вашим значением 2 Затем этот будет назначен первому, а временный экземпляр будет удален до того, как произойдет ваш std :: cout! В тот момент, когда вы покинете область действия основной функции, первый экземпляр будет удален!

Что вы можете узнать:

  • создание объекта с помощью X x=X(3); аналогично записи X x(3);
  • , если вы не написали оператор присваивания вручную, вы можете получить оператор по умолчанию, в зависимости от некоторых других правил (для более широкого здесь).
  • вы должны видеть, что здесь вы создаете временные объекты, которые будут создаваться и удаляться «на лету», но при этом иметь стоимость, которой в большинстве случаев можно избежать!
  • вам следует не [ 119] используйте using namespace std!
  • вы должны написать X x{3} instead of X x (3) `
  • написание X x=X(3); полностью сбивает с толку, так как похоже, что вы создаете временное и затем назначаете это по умолчанию построен один. Но этого не произойдет, и поэтому вы должны написать свой код проще!
26
задан Community 23 May 2017 в 12:18
поделиться

7 ответов

Разрешается объявлять переменную в управляющей части вложенного блока, но в случае if и while переменная должна быть инициализирована числовым или логическим значением, которое будет интерпретировано как условие , Его нельзя включить в более сложное выражение!

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

Лично я считаю хорошей практикой сохранять локальные переменные как можно ближе к их фактическому времени жизни в коде, даже если это звучит шокирующе, когда вы переходите с C на C ++ или с Pascal на C ++ - мы привыкли видеть переменные в одном месте. С некоторой привычкой, вы находите его более читабельным, и вам не нужно искать в другом месте, чтобы найти объявление. Более того, вы знаете, что до этого момента он не использовался.


Редактировать:

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

Поэтому вместо того, чтобы использовать это:

int i;
if((i = read(socket)) < 0) {
    // handle error
}
else if(i > 0) {
    // handle input
}
else {
    return true;
}

Я бы предпочел, чтобы:

int i = read(socket);
if(i < 0) {
    // handle error
}
else if(i > 0) {
    // handle input
}
else {
    return true;
}
18
ответ дан RedGlyph 28 November 2019 в 07:06
поделиться

Я использую const как можно больше в этих ситуациях. Вместо вашего примера я бы сделал:

const int readResult = read(socket);
if(readResult < 0) {
    // handle error
} 
else if(readResult > 0)
{
    // handle input
} 
else {
    return true;
} 

Так что, хотя область действия не содержится, это не имеет значения, так как переменная не может быть изменена.

6
ответ дан Bill 28 November 2019 в 07:06
поделиться

Я столкнулся с похожей проблемой :

Проблема, кажется, заключена в круглые скобки вокруг объявления int. Это должно работать, если вы можете выразить задание и протестировать без них, т.е.

if (int i = read(socket)) {

должно работать, но это означает, что тест - != 0, а это не то, что вам нужно.

4
ответ дан Community 28 November 2019 в 07:06
поделиться

Добавление к тому, что сказали Редглиф и Ферруччо. Может быть, мы можем сделать следующее, чтобы по-прежнему объявлять в условном выражении ограничение его использования:

if(int x = read(socket)) //x != 0
{
  if(x < 0) //handle error
  {}
  else //do work
  {}
}
else //x == 0  
{
  return true;
}
3
ответ дан Piotr99 28 November 2019 в 07:06
поделиться

Хотя это и не связано напрямую с вопросом, все примеры ставят обработку ошибок на первое место. Поскольку существует 3 случая (> 0 -> данные, == 0 -> соединение закрыто и < 0 -> ошибка), это означает, что наиболее распространенный случай получения новых данных требует двух тестов. Проверка на> 0 сначала сократила бы ожидаемое количество тестов почти вдвое. К сожалению, подход «if (int x = read (socket))», предоставленный White_Pawn, по-прежнему требует 2 теста для случая данных, но предложение C ++ 17 можно было бы использовать для проверки сначала на> 0.

0
ответ дан Jim Monte 28 November 2019 в 07:06
поделиться

Я считаю это хорошим стилем при использовании, возможно, с указателем NULL:

if(CObj* p = GetOptionalValue()) {
   //Do something with p
}

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

С другой стороны, по крайней мере, в VC ++ это единственное поддерживаемое использование (т.е. проверка истинности присвоения)

11
ответ дан 28 November 2019 в 07:06
поделиться

Хотя вы можете использовать объявление как логическое выражение, вы не можете разместить объявление в середине выражения. Я не могу избавиться от мысли, что вы неправильно читаете то, что говорит Бьярн.

Этот метод полезен и желателен в основном для управляющих переменных циклов for, но в данном случае я считаю опрометчивым и не дает ясности. И конечно не работает! ;)

if( <type> <identifier> = <initialiser> ) // valid, but not that useful IMO

if( (<type> <identifier> = <initialiser>) <operator> <operand> )  // not valid

for( <type> <identifier> = <initialiser>; 
     <expression>; 
     <expression> )  // valid and desirable

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

3
ответ дан 28 November 2019 в 07:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: