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);
using namespace std
! X x{3} instead of
X x (3) `X x=X(3);
полностью сбивает с толку, так как похоже, что вы создаете временное и затем назначаете это по умолчанию построен один. Но этого не произойдет, и поэтому вы должны написать свой код проще! Разрешается объявлять переменную в управляющей части вложенного блока, но в случае 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;
}
Я использую const как можно больше в этих ситуациях. Вместо вашего примера я бы сделал:
const int readResult = read(socket);
if(readResult < 0) {
// handle error
}
else if(readResult > 0)
{
// handle input
}
else {
return true;
}
Так что, хотя область действия не содержится, это не имеет значения, так как переменная не может быть изменена.
Я столкнулся с похожей проблемой :
Проблема, кажется, заключена в круглые скобки вокруг объявления int
. Это должно работать, если вы можете выразить задание и протестировать без них, т.е.
if (int i = read(socket)) {
должно работать, но это означает, что тест - != 0
, а это не то, что вам нужно.
Добавление к тому, что сказали Редглиф и Ферруччо. Может быть, мы можем сделать следующее, чтобы по-прежнему объявлять в условном выражении ограничение его использования:
if(int x = read(socket)) //x != 0
{
if(x < 0) //handle error
{}
else //do work
{}
}
else //x == 0
{
return true;
}
Хотя это и не связано напрямую с вопросом, все примеры ставят обработку ошибок на первое место. Поскольку существует 3 случая (> 0 -> данные, == 0 -> соединение закрыто и < 0 -> ошибка), это означает, что наиболее распространенный случай получения новых данных требует двух тестов. Проверка на> 0 сначала сократила бы ожидаемое количество тестов почти вдвое. К сожалению, подход «if (int x = read (socket))», предоставленный White_Pawn, по-прежнему требует 2 теста для случая данных, но предложение C ++ 17 можно было бы использовать для проверки сначала на> 0.
Я считаю это хорошим стилем при использовании, возможно, с указателем NULL:
if(CObj* p = GetOptionalValue()) {
//Do something with p
}
Таким образом, независимо от того, объявлен ли p, это действительный указатель. Отсутствие опасности доступа к висячим указателям.
С другой стороны, по крайней мере, в VC ++ это единственное поддерживаемое использование (т.е. проверка истинности присвоения)
Хотя вы можете использовать объявление как логическое выражение, вы не можете разместить объявление в середине выражения. Я не могу избавиться от мысли, что вы неправильно читаете то, что говорит Бьярн.
Этот метод полезен и желателен в основном для управляющих переменных циклов 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 - плохая идея, независимо от того, что вы думаете об объявлении переменной там.