Pergunta

class mystring {
 friend ostream& operator<<(ostream &out, const mystring ss) {
        out << ss.s;
        return out;
    }
private:
    string s;
public:
    mystring(const char ss[]) {
        cout << "constructing mystring : " << ss << endl;
        s = ss;
    }
};

void outputStringByRef(const mystring &ss) {
 cout << "outputString(const string& ) " << ss << endl;
}

void outputStringByVal(const mystring ss) {
 cout << "outputString(const string ) " << ss << endl;
}

int main(void) {
    outputStringByRef("string by reference");
    outputStringByVal("string by value");
    outputStringByRef(mystring("string by reference explict call mystring consructor"));
    outputStringByVal(mystring("string by value explict call mystring constructor"));
} ///:~

Considerando o exemplo acima, não conseguimos modificar a variável de passagem por referência, também não poderíamos modificar a variável de passagem por valor. A saída de cada métodos é a mesma. Como não há diferença entre esses dois métodos, por que C ++ Suportar os dois métodos?

obrigado.

Foi útil?

Solução

Há uma diferença entre os dois. Considere o seguinte:

#include <iostream>
#include <string>
using std::string;

string g_value;

void callback() {
    g_value = "blue";
}

void ProcessStringByRef(const string &s) {
    callback();
    std::cout << s << "\n";
}

void ProcessStringByValue(const string s) {
    callback();
    std::cout << s << "\n";
}

int main() {
    g_value = "red";
    ProcessStringByValue(g_value);
    g_value = "red";
    ProcessStringByRef(g_value);
}

Resultado:

red
blue

Só porque uma referência é const em uma função, não significa que o referente não possa ser modificado por outras referências (a situação de um objeto com várias referências ou ponteiros é chamado de "aliasing"). Portanto, existe uma diferente entre a passagem de uma referência const e a aprovação de um valor const - no caso da referência, o objeto pode mudar após a chamada. No caso do valor, o Callee possui uma cópia privada, que não será alterada.

Como eles fazem coisas diferentes, o C ++ permite escolher o que você deseja.

De qualquer forma, existem consequências para o desempenho - quando você passa por valor, uma cópia deve ser feita, quais custos. Mas o compilador sabe então que apenas sua função pode ter referências a essa cópia, o que pode permitir outras otimizações. ProcessStringByref não pode carregar o conteúdo da string para imprimir até callback() Voltou. ProcessStringByValue pode, se o compilador achar que isso é mais rápido.

Geralmente você se preocupa com a cópia, não com a ordem de execução de instruções, porque geralmente a cópia é muito mais cara. Normalmente, você passa por referência sempre que possível para objetos que não são triviais para copiar. Mas a possibilidade de alias às vezes tem consequências realmente sérias para o desempenho, impedindo certas otimizações, mesmo que nenhum alias realmente ocorra. É por isso que "regras estritas de alias" existem, e o restrict Palavra -chave em C99.

Outras dicas

f(const string&) pega string by const referência: festá operando diretamente no objeto String passado por referência: não há cópia envolvida. const Evita modificações no objeto original.

f(const string) leva um valor de string, o que significa f recebe uma cópia da string original. Mesmo se você cair const, ao passar por valor, qualquer modificação para a string é perdida quando f retorna.

Não sei exatamente o que você quer dizer com "Por que o C ++ suporta os dois métodos?". São apenas regras gerais de sobrecarga que se aplicam.

f(string s) Passe pelo valor da string s, em outras palavras, cria uma cópia e a inicializa com o valor da string que você passa. Qualquer alteração na cópia não será propagada para a string original que você passou para chamar a função. Dentro f(const string s) Const é redundante porque você não pode alterar o valor original.

Dentro f(const string& s) Em vez disso, a string não é copiada, mas você passa uma referência a ela. Isso geralmente é feito quando você tem um objeto grande para que o "valor por valor" possa produzir uma sobrecarga (é por isso que o C ++ suporta os dois métodos). Passar por referência significa que você pode alterar o valor do objeto "grande" que você passa, mas, devido ao especificador const, você não pode modificá -lo. É uma espécie de "proteção".

Seu objeto pode conter um mutável membro, que pode ser modificado mesmo com uma referência const

Com outputStringByRef você deve garantir que a variável a que está passando permanece viva e inalterada pelo tempo que outputStringByRef precisa disso. com outputStringByVal A variável que você passou pode morrer ou sair do escopo e a cópia que a função tem ainda está bem.

(Quase) não há diferença em termos de poder modificar a string dentro da função. No entanto, há uma grande diferença em termos do que está sendo aprovado. o const mystring &ss Sobrecarga requer uma referência const para a string. Embora não possa modificá -lo, é a mesma memória que está sendo abordada. Se a string for longa, isso pode ser um grande fator (assumindo que a string não seja implementada usando cópia-em-escrever). o const mystring ss O formulário está fazendo uma cópia da string, para que a memória diferente seja abordada.

Na verdade const mystring &ss Formato poderia Altere a string, se um const_cast<mystring&> foi usado - embora eu não recomendaria isso aqui.

Imagine que você deseja imprimir um objeto que não possa ser copiado:

Thread th;
// ...
cout << th; // print out informations...

A versão de referência não copiará o tópico, mas levará o endereço de th e crie um pseudônimo para ele. A outra versão tentaria copiar o thread ao passar por valor - mas a cópia pode não ser sentida para esse objeto (haveria um thread adicional então?).

Pode ajudá -lo a pensar em copie um objeto Como clonando um objeto. Cópia th Acima em C ++, não significa apenas ter outra alça para o mesmo objeto que em Java - significa clonar implicitamente o objeto denotado e ter uma cópia inteira dele. Portanto, a pergunta é semelhante a "Por que Java suporta ambos Object.clone e cópia de referências? " - ambos têm propósitos diferentes.

E também há uma questão de desempenho, afinal. Você não deseja copiar sempre que passa algo para obter objetos com fome de recursos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top