#c #pointers
#c #указатели
Вопрос:
Я хочу начать с того, что я работал с указателями раньше, и я предполагал, что понимаю, как они работают. Как в,
int x = 5;
int *y = amp;x;
*y = 3;
std::cout << x; // Would output 3
Но затем я захотел создать метод, который изменяет довольно большую строку, и я полагаю, поэтому было бы лучше передать ссылку на строку, чтобы избежать передачи всей строки обратно и четвертой. Итак, я передаю свою строку в myFunc()
и делаю то же самое, что и с приведенными выше числами. Это означает, что я могу вносить изменения *str
, как я делаю в приведенном ниже коде. Но для того, чтобы использовать методы для, String
мне нужно использовать ->
оператор.
#include <iostream>
#include <string>
int myFunc(std::string *str) { // Retrieve the address to which str will point to.
*str = "String from myFunc"; // This is how I would normally change the value of myString
str->replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
return 0;
}
int main() {
std::string myString << "String from main";
myFunc(amp;myString); // Pass address of myString to myFunc()
}
Мои вопросы:
- Поскольку
str
в myFunc есть адрес, почему адрес может использовать такой оператор, как->
и как это работает? Это так же просто, как используется метод объекта по адресуstr
?str->replace(); // str->myString.replace()?
- Является ли это хорошей реализацией для изменения большой строки или было бы лучше передать строку методу и вернуть строку при ее изменении??
Комментарии:
1. 1)
->
сделает 2 вещи: разыменует указатель, а затем получит доступ и вызовreplace()
2) Я бы выбрал передачу по ссылке (однако в конечном итоге это то же самое, что и передача по указателю)
Ответ №1:
ptr->x
идентично, (*ptr).x
если ->
не переопределено для типа, который вы разыменовываете. На обычных указателях это работает так, как вы и ожидали.
Что касается реализации, профилируйте ее при ее реализации. Вы не можете знать, что компилятор будет делать с этим, как только вы включите оптимизацию. Например, если данная функция будет встроена, у вас даже не будет дополнительной косвенности в первую очередь, и не будет иметь значения, каким способом вы это сделаете. Пока вы не выделяете новую строку, различия, как правило, должны быть незначительными.
Ответ №2:
str
является указателем на std::string
объект. Оператор arrow, ->
, используется для разыменования указателя и последующего доступа к его элементу. В качестве альтернативы вы также можете написать (*str).replace(0,1,"s")
; здесь *
разыменовывается указатель, а затем .
осуществляется доступ к функции-члену replace()
.
Указатели часто сбивают с толку; лучше использовать ссылки, когда это возможно.
void myFunc(std::string amp;str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}
int main() {
std::string myString = "String from main";
myFunc(myString); // Pass address of myString to myFunc()
}
Является ли это хорошей реализацией для изменения большой строки или было бы лучше передать строку методу и вернуть строку при ее изменении??
Если вы не хотите изменять исходную строку, создайте новую строку и верните ее.
Если для вашего приложения нормально изменять исходную строку, сделайте это. Также вы можете вернуть ссылку на измененную строку, если вам нужно связать вызовы функций.
std::stringamp; myFunc(std::string amp;str) { // Retrieve the address to which str will point to.
str = "String from myFunc"; // This is how I would normally change the value of myString
return str.replace(0, 1, "s"); // Replacing index 0 with a lowercase s.
}
Комментарии:
1. Итак, когда вы передаете по ссылке, вы извлекаете адрес в,
myFunc(std::string amp;str)
даже если вы передаетеmyString
при его вызове? Означает ли это, чтоamp;str == amp;myString // equals true?
2. ссылки лучше понимать как псевдонимы. Я предполагаю, что ваша путаница возникает из-за operator
amp;
. Когда он используется во время объявления, например,int amp;i = a;
, он объявляет псевдоним для исходной переменной. (Обратите внимание, что ссылки должны быть инициализированы во время объявления, и их нельзя переназначить.) с другой стороны,amp;a
используется после того, как вы уже объявили переменнуюa
и хотите получить ее адрес, вот почему он также называетсяaddressof
operator .amp;str
не совпадает сamp;myString
3. Когда бы я когда-нибудь использовал
int amp;i = a;
, если бы это было не то же самое?4. @darclander Это был просто пример, показывающий синтаксис. В основном вы будете использовать ссылочные переменные в качестве параметра. Если параметр изменен, это фактически повлияет на значение аргумента (значение, передаваемое функции). Пожалуйста, ознакомьтесь с часто задаваемыми вопросами о ссылках