С ++ переменное присваивание, это нормальный способ ..?

Это может быть глупый вопрос, но все же мне немного любопытно …
Недавно я работал над одним из моих проектов бывших коллег, и я заметил, что он действительно любил использовать что-то вроде этого:

int foo(7);

вместо:

int foo = 7;

Это нормальный / хороший способ сделать это на языке C ++?
Есть ли какая-то польза от этого? (Или это просто какой-то глупый стиль программирования, которым он увлекался?)

Это действительно напоминает мне хороший способ, как переменные-члены класса могут быть назначены в конструкторе класса … что-то вроде этого:

class MyClass
{
public:
MyClass(int foo) : mFoo(foo)
{ }

private:
int   mFoo;
};

вместо этого:

class MyClass
{
public:
MyClass(int foo)
{
mFoo = foo;
}

private:
int   mFoo;
};

8

Решение

Для основных типов нет никакой разницы. Используйте то, что согласуется с существующим кодом и выглядит более естественным для вас.

Иначе,

A a(x);

выполняет прямая инициализация, а также

A a = x;

выполняет инициализация копии.

Вторая часть — это список инициализирующих членов, есть куча Q&Как об этом на StackOverflow.

8

Другие решения

Оба действительны. Для встроенных типов они делают то же самое; для типов классов есть небольшая разница.

MyClass m(7);  // uses MyClass(int)
MyClass n = 3; // uses MyClass(int) to create a temporary object,
// then uses MyClass(const MyClass&) to copy the
// temporary object into n

Очевидное значение заключается в том, что если MyClass не имеет конструктора копирования, или он есть, но он недоступен, попытка создания завершается неудачей. Если конструкция будет успешной, компилятору будет позволено пропустить конструктор копирования и использовать MyClass(int) непосредственно.

3

Все ответы выше верны. Просто добавьте к этому, что C ++ 11 поддерживает другой способ, как говорят, для инициализации переменных.

int a = {2} ;

или же

int a {2} ;
3

Несколько других хороших ответов указывают на разницу между конструированием «на месте» (ClassType v(<constructor args>)) и создание временного объекта и использование конструктора копирования для его копирования (ClassType v = <constructor arg>). Я думаю, что нужно сделать еще два замечания. Во-первых, вторая форма, очевидно, имеет только один аргумент, поэтому, если ваш конструктор принимает более одного аргумента, вы должны предпочесть первую форму (да, есть способы обойти это, но я думаю, что прямая конструкция более краткая и удобочитаемая — но , как уже было отмечено, это личное предпочтение).

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

2

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

Желаете ли вы использовать его для нормальной инициализации основных типов — это предпочтение стиля.

Обратите внимание, что C ++ 11 также добавляет единый синтаксис инициализации который позволяет использовать один и тот же стиль инициализации для всех типов — даже для агрегатов, таких как структуры и массивы POD (хотя для пользовательских типов может потребоваться новый тип конструктора, который принимает список инициализации, чтобы позволить использовать с ними унифицированный синтаксис ).

2

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

class A {
public:
A() {}
};

а также

class B {
public:
class B(A const &) {}
};

Пишу

B b = B(A());

Требует, чтобы конструктор копирования B был доступен. Пишу

B b = A();

Требуется также, чтобы преобразователь B преобразовал B (A const &не быть объявленным явным. С другой стороны, если вы напишите

A a;
B b(a);

все хорошо, но если пишешь

B b(A());

Это интерпретируется компилятором как объявление функции b, которая принимает безымянный аргумент, который является функцией без параметров, возвращающей A, что приводит к таинственным ошибкам. Это известно как C ++ самый неприятный анализ.

2

Я предпочитаю использовать стиль в скобках … хотя я всегда использую пробел, чтобы отличать вызовы функций или методов, в которых я не использую пробел:

int foo (7); // initialization
myVector.push_back(7); // method call

Одна из причин, по которой я предпочитаю использовать это для всех целей инициализации, заключается в том, что это помогает напомнить людям, что это не назначение. Следовательно, перегрузки для оператора присваивания не будут применяться:

#include <iostream>

class Bar {
private:
int value;
public:
Bar (int value) : value (value) {
std::cout << "code path A" << "\n";
}
Bar& operator=(int right) {
value = right;
std::cout << "code path B" << "\n";
return *this;
}
};

int main() {
Bar b = 7;
b = 7;
return 0;
}

Выход:

code path A
code path B

Такое ощущение, что наличие знака равенства скрывает разницу. Даже если это «общеизвестно», мне нравится, чтобы инициализация выглядела заметно иначе, чем назначение, так как мы можем это сделать.

2

Это просто синтаксис для инициализации чего-либо:

SomeClass data(12, 134);

Это выглядит разумно, но

int data(123);

Выглядит странно, но они имеют одинаковый синтаксис.

1