Por que use = para inicializar um tipo primitivo em C ++?

votos
8

Onde eu trabalho, principalmente as pessoas pensam que os objetos são melhor inicializado usando C ++ - construção de estilo (com parênteses), enquanto que os tipos primitivos deve ser iniciado com o operador =:

std::string strFoo( Foo );
int nBar = 5;

Ninguém parece ser capaz de explicar por que eles preferem as coisas desta maneira, embora. Eu posso ver que std::string = Foo;seria ineficiente porque envolveria uma cópia extra, mas o que há de errado com apenas banir o =operador completamente e usando parênteses em todos os lugares?

É uma convenção comum? Qual é o pensamento por trás disso?

Publicado 09/12/2008 em 18:52
fonte usuário
Em outras línguas...                            


9 respostas

votos
17

Inicializar variáveis ​​com o operador = ou com uma chamada de construtor são semanticamente o mesmo, é apenas uma questão de estilo. Eu prefiro o operador =, pois ele lê mais naturalmente.

Usando o operador = normalmente não gera uma cópia extra - ele só chama o construtor normal. Note-se, no entanto, que com os tipos não-primitivos, isto é apenas para inicializações que ocorrem ao mesmo tempo que as declarações. Comparar:

std::string strFooA("Foo");  // Calls std::string(const char*) constructor
std::string strFoo = "Foo";  // Calls std::string(const char*) constructor
                             // This is a valid (and standard) compiler optimization.

std::string strFoo;  // Calls std::string() default constructor
strFoo = "Foo";      // Calls std::string::operator = (const char*)

Quando você tem construtores padrão não-triviais, a última construção pode ser um pouco mais ineficiente.

O padrão C ++ , secção 8.5, n.º 14 estados:

Caso contrário (isto é, para os restantes processos de cópia de inicialização), um temporária é criada. Sequências de conversão definida pelo utilizador que podem converter a partir do tipo de fonte para o tipo de destino ou uma classe de derivados dos mesmos são enumerados (13.3.1.4), e o melhor é escolhido por meio de resolução de sobrecarga (13,3). A conversão definido pelo utilizador, de modo seleccionado é chamado para converter a expressão em um inicializador temporária, cujo tipo é do tipo retornado pela chamada da função de conversão definido pelo utilizador, com os CV-qualificadores do tipo de destino. Se a conversão não pode ser feito ou é ambígua, a inicialização é mal-formado. O objecto a ser inicializada é, em seguida, dirigir-inicializada a partir do temporária de acordo com as regras acima. 87 )Em certos casos, uma aplicação é permitida para eliminar o temporária por inicializar o objecto directamente; ver 12.2.

Parte da seção 12.2 estados:

Mesmo quando a criação do objeto temporário é evitado, todas as restrições semânticas devem ser respeitados como se o objeto temporário foi criado. [Exemplo: mesmo que o construtor de cópia não é chamado, todas as restrições semânticas, tais como a acessibilidade (11), deve ser satisfeita. ]

Respondeu 09/12/2008 em 18:57
fonte usuário

votos
11

Eu apenas senti a necessidade de um outro post litb bobo.

string str1 = "foo";

é chamado de cópia de inicialização , porque o que o compilador faz, se não elide quaisquer temporários, é:

string str1(string("foo")); 

ao lado de verificar que o construtor de conversão utilizado é implícito. Na verdade, todas as conversões implícitas são definidas pelo padrão em termos de inicialização cópia. Diz-se que uma conversão implícita de tipo U digitar T é válido, se

T t = u; // u of type U

é válido.

Em contraste,

string str1("foo");

está fazendo exatamente o que está escrito, e é chamado de inicialização direta . Ele também funciona com construtores explícitos.

By the way, você pode desativar eliding de temporários usando -fno-Elide-construtores:

-fno-elide-constructors
    The C++ standard allows an implementation to omit creating a temporary which 
    is only used to initialize another object of the same type. Specifying this 
    option disables that optimization, and forces G++ to call the copy constructor 
    in all cases.

The Standard diz que não há praticamente nenhuma diferença entre

T a = u;

e

T a(u);

Se T eo tipo de u são tipos primitivos. Assim, você pode usar as duas formas. Eu acho que é apenas o estilo dele que faz com que as pessoas usam a primeira forma em vez do segundo.


Algumas pessoas podem usar o primeiro em alguma situação, porque eles querem ambigüidade da declaração:

T u(v(a));

migh olhar para alguém como uma definição de uma variável uque é inicializado usando um temporária de um tipo vque recebe um parâmetro para o construtor chamado a. Mas, na verdade, o que o compilador faz com que é esta:

T u(v a);

Ele cria uma declaração de função que leva um argumento do tipo v, e com um parâmetro chamado a. Então, as pessoas fazem

T u = v(a);

para disambiguate que, embora eles poderiam ter feito

T u((v(a)));

também, porque nunca há parênteses em torno parâmetros da função, o compilador iria lê-lo como uma definição variável em vez de uma declaração de função também :)

Respondeu 09/12/2008 em 19:21
fonte usuário

votos
4

A menos que você já provou que é importante no que diz respeito ao desempenho, eu não me preocuparia com uma cópia extra usando o operador de atribuição no seu exemplo ( std::string foo = "Foo";). Eu ficaria muito surpreso se essa cópia existe mesmo uma vez que você olhar para o código otimizado, acredito que vai realmente chamar o construtor com parâmetros adequados.

Em resposta à sua pergunta, sim, eu diria que é uma convenção muito comum. Classicamente, as pessoas têm usado atribuição para inicializar tipos built-in, e não há uma razão convincente para mudar a tradição. Legibilidade e hábito são perfeitamente razões válidas para esta convenção dado o pouco impacto que tem sobre o código final.

Respondeu 09/12/2008 em 18:59
fonte usuário

votos
2

Você provavelmente vai achar que o código como

std::string strFoo = "Foo";

vai evitar fazer uma cópia extra e compila para o mesmo código (uma chamada de um construtor de argumento único) como o único com parênteses.

Por outro lado, há casos em que um deve usar parênteses, como uma lista de inicialização membro do construtor.

Eu acho que o uso de = ou parênteses para construir as variáveis ​​locais é em grande parte uma questão de escolha pessoal.

Respondeu 09/12/2008 em 18:57
fonte usuário

votos
1

Bem, quem sabe o que eles pensam, mas eu também prefiro as = para tipos primitivos, principalmente porque eles não são objetos, e porque essa é a maneira "usual" para inicializar-los.

Respondeu 09/12/2008 em 18:58
fonte usuário

votos
0

Mas, em seguida, apenas para confundi-lo ainda mais você inicializar primitivas na lista de inicialização usando a sintaxe do objeto.

foo::foo()   
  ,anInt(0)   
  ,aFloat(0.0)   
{   
}   
Respondeu 09/12/2008 em 19:44
fonte usuário

votos
0

Um argumento que se pode fazer para:

foo std :: string ( "bar");

É que ele mantém as coisas da mesma, mesmo se o argumento contar mudanças, ou seja:

foo std :: string ( "bar", 5);

Não funciona com um sinal '='.

Outra coisa é que, para muitos objetos de um '=' sente não natural, por exemplo, dizer que você tem uma classe Array onde o argumento dá o comprimento:

Matriz arr = 5;

não se sentir bem, uma vez que não construir uma matriz com o valor 5, mas com comprimento de 5:

Arr matriz (5);

se sente mais natural, já que você está construindo um objeto com o parâmetro dado, não apenas copiando um valor.

Respondeu 09/12/2008 em 19:36
fonte usuário

votos
0

Eu acredito que é mais de um hábito, muito poucos objetos podem ser inicializados usando =, a string é um deles. É também uma maneira de fazer o que você disse "usando parênteses em todos os lugares (que a língua permite que você usá-lo)"

Respondeu 09/12/2008 em 18:59
fonte usuário

votos
0

É uma questão de estilo. Mesmo a afirmação de que "std :: string = 'Foo'; seria ineficiente porque envolveria uma cópia extra" não é correto. Este "cópia extra" é removido pelo compilador.

Respondeu 09/12/2008 em 18:57
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more