Как работает оператор ‘->’ и является ли это хорошей реализацией для изменения большой строки?

#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 Это был просто пример, показывающий синтаксис. В основном вы будете использовать ссылочные переменные в качестве параметра. Если параметр изменен, это фактически повлияет на значение аргумента (значение, передаваемое функции). Пожалуйста, ознакомьтесь с часто задаваемыми вопросами о ссылках