Вопрос

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"));
} ///:~

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

Спасибо.

Это было полезно?

Решение

Между ними есть разница.Учтите следующее:

#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);
}

Выход:

red
blue

Тот факт, что ссылка является константой внутри функции, не означает, что ссылка не может быть изменена с помощью других ссылок (ситуация, когда один объект имеет несколько ссылок или указателей на него, называется «алиасингом»).Таким образом, существует разница между передачей константной ссылки и передачей константного значения: в случае ссылки объект может измениться после выполнения вызова.В случае значения у вызываемого объекта есть частная копия, которая не изменится.

Поскольку они делают разные вещи, C++ позволяет вам выбрать то, что вы хотите.

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

Обычно вас волнует копия, а не порядок выполнения инструкций, потому что обычно копия обходится намного дороже.Поэтому обычно вы передаете по ссылке, где это возможно, объекты, копирование которых не является тривиальным.Но возможность наложения псевдонимов иногда имеет очень серьезные последствия для производительности, поскольку препятствует определенным оптимизациям, хотя на самом деле псевдонимов не происходит.Вот почему существуют «строгие правила псевдонимов», и restrict ключевое слово в C99.

Другие советы

f(const string&) принимает строку за const ссылка: fработает непосредственно со строковым объектом, передаваемым по ссылке:здесь нет никакой копии. const однако предотвращает изменение исходного объекта.

f(const string) принимает строковое значение, что означает f предоставляется копия исходной строки.Даже если ты уронишь const, при передаче по значению любые изменения строки теряются, если f возвращается.

Я не знаю точно, что вы подразумеваете под «почему C++ поддерживает оба метода?».Применяются только общие правила перегрузки.

f(string s) передать по значению строку s, другими словами, он создает копию и инициализирует ее значением передаваемой строки.Любые изменения в копии не будут распространены на исходную строку, которую вы передали для вызова функции.В f(const string s) const является избыточным, поскольку вы все равно не сможете изменить исходное значение.

В f(const string& s) вместо этого строка не копируется, а вы передаете на нее ссылку.Обычно это делается, когда у вас есть большой объект, поэтому «передача по значению» может привести к накладным расходам (вот почему C++ поддерживает оба метода).Передача по ссылке означает, что вы можете изменить значение передаваемого «большого» объекта, но из-за спецификатора const вы не можете его изменить.Это своего рода «защита».

ваш объект может содержать изменчивый член, который можно изменить даже с помощью константной ссылки

С outputStringByRef вы должны убедиться, что переменная, на которую вы передаете ссылку, остается активной и неизменной до тех пор, пока outputStringByRef это нужно.с outputStringByVal переданная вами переменная может умереть или выйти из области видимости, а копия, которую имеет функция, все еще в порядке.

Нет (почти) никакой разницы в плане возможности изменять строку внутри функции.Однако существует большая разница в том, что передается.Тот Самый const mystring &ss перегрузка принимает постоянную ссылку на строку.Хотя он не может изменить его, адресуется та же самая память.Если строка длинная, это может быть важным фактором (при условии, что строка не реализована с использованием копирование при записи).Тот Самый const mystring ss форма создает копию строки, поэтому будет адресована другая память.

На самом деле const mystring &ss форма мог бы измените строку, если a const_cast<mystring&> был использован - хотя я бы не рекомендовал этого здесь.

Представьте, что вы хотите напечатать объект, который невозможно скопировать:

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

Эталонная версия не будет копировать поток, а возьмет адрес th и создайте для него псевдоним.Другая версия попытается скопировать поток при передаче по значению, но копирование может быть бессмысленным для такого объекта (будет ли тогда еще один дополнительный поток?).

Это может помочь вам подумать о скопировать объект как клонирование объекта.Копирование th выше в C++ не просто означает наличие другого дескриптора того же объекта, что и в Java, - это означает неявное клонирование обозначенного объекта и получение его полной копии.Итак, вопрос похож на «Почему Java поддерживает оба Object.clone и копирование ссылок?" - у обоих разные цели.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top