Как передать ссылки по значению в C ++? - PullRequest
2 голосов
/ 16 марта 2009

Я пытаюсь создать неизменный тип (класс) в C ++,

Я сделал так, чтобы все методы, называемые «функциями-членами», не модифицировали объект и вместо этого возвращали новый экземпляр.

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

Один пример - передача параметров одного и того же типа класса по ссылке:

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   p_im = p_im.someOtherOp(); //error, p_im is const, can't modify it!
   ...
}

Ошибка вызвана передачей значения по ссылке. Если бы вместо этого я передавал ссылку по значению, то приведенная выше строка ошибки не была бы ошибкой!

Рассмотрим пример Java / C #

class Imm
{
    ...
    Imm someOp( Imm p_im )
    {
        ....
        p_im = p_im.someOtherOp(); //ok, you're not modifying the 
                 //original object, just changing the local reference
        ....  
    }
    ....
}

Как я могу сделать что-то подобное в C ++? Я знаю, что могу использовать указатели, но затем я сталкиваюсь со всем беспорядком управления памятью. Я не хочу беспокоиться о том, кто владеет ссылками на объекты.

В идеале я бы хотел, чтобы класс был похож на неизменяемые строки в python; вы можете использовать их, даже не замечая и даже не зная, что они неизменны, и они просто ведут себя так, как вы ожидаете; они просто работают.

EDIT

Конечно, я могу обойти это, передавая по значению или используя временную переменную (что я сейчас и делаю). Я спрашиваю о том, «как передавать ссылки по значению в C ++»

Я ожидаю, что ответ будет вращаться вокруг чего-то в STL, сейчас я изучаю семейство шаблонов smart_ptr.

UPDATE

Спасибо за ответы, я понимаю, что нет указателей. (см. мой другой вопрос , который действительно является продолжением этого вопроса)

Ответы [ 6 ]

4 голосов
/ 16 марта 2009

В Java и C # вы на самом деле не имеете дело со ссылками - они больше похожи на дескрипторы или указатели. Ссылка в C ++ - это действительно другое имя для исходного объекта, а не указатель на него (хотя он может быть реализован с помощью указателя). Когда вы назначаете значение для ссылки, вы присваиваете сам объект. Существует путаница в том, что для инициализации ссылки вы можете использовать символ =, но это инициализация, а не присвоение.

 Imm im, im2, im3; 
 Imm &imr = im;  // initialize a reference to im
 imr = im2; // assign im2 to imr (changes the value of im as well)
 Imm *imp = &im; // initialize a pointer to the address of im
 imp = &im3; // assign the address of im3 to imp (im is unnaffected);
 (*imp) = im2; // assign im2 to imp (modifies im3 as well).

Если вы специально хотите передать «ссылки по значению», то вы, по сути, запрашиваете противоречие в терминах. Ссылки по определению передаются по ссылке. Как указано в другом месте, вы можете передать указатель по значению или же прямое значение. Если вы действительно хотите, вы можете удерживать ссылку в классе и передавать ее по значению:

 struct ImmRef
 {
     Imm &Ref;
     ImmRef(Imm &ref) : Ref(ref) {}
 };

Обратите внимание также, что const, примененный к ссылке, делает константу объекта ссылки постоянной, а не ссылку. Ссылки всегда постоянны.

4 голосов
/ 16 марта 2009

Не является ли присвоение по определению не постоянной операцией?

Похоже, вы пытаетесь присвоить что-то константной ссылке, что полностью опровергает идею константной ссылки.

Я думаю, вы можете искать указатель вместо ссылки.

3 голосов
/ 16 марта 2009

Это не работает так в C ++.

Когда вы передаете ссылку на объект, вы фактически передаете адрес в памяти объекта. Ссылки не могут быть повторно размещены на других объектах, следовательно, пословица C ++ «ссылка - это объект» Вы должны сделать копию, чтобы изменить ее. Java сделает это за кулисами для вас. C ++, вам просто нужно скопировать его.

1 голос
/ 16 марта 2009

Разве вы не забыли установить вызываемый метод как const?

РЕДАКТИРОВАТЬ: итак, с фиксированным const.

Может быть, вы должны сделать что-то вроде

Imm & tmp = p_im.someOtherOp();

Затем выполните дальнейшую операцию с переменной tmp.

Если вы установите переменную или параметр как const, и вы просто не можете назначить их.

0 голосов
/ 16 марта 2009

Отметьте это, чтобы узнать о временном сроке жизни http://herbsutter.wordpress.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   //Imm& im = p_im.someOtherOp();       // will *not* work
   const Imm& im = p_im.someOtherOp();   // will work, but you get a const reference
   ...
}

Но вы можете использовать boost :: shared_ptr

shared_ptr<Imm> Imm::someOtherOp() const
{
  shared_ptr<Imm> ret = new Imm;
  ...
  return ret;
}

shared_ptr<Imm> Imm::someOp(const share_ptr<Imm>& p_im) const
{
  shared_ptr<Imm> im = p_im->someOtherOp();
}
0 голосов
/ 16 марта 2009

Вам нужно сделать новую копию вашего входящего аргумента. Вы можете делать то, что хотите, несколькими эквивалентными способами: 1) вы можете передавать по значению:

Imm Imm::someOp( Imm im ) const {
   im = im.someOtherOp();      // local im is a copy, original im not modified
   return im;                  // return by value (another copy)
}

или 2) вы можете перейти по ссылке и сделать копию явно:

Imm Imm::someOp( const Imm & im ) const {
   Imm tmp = im.someOtherOp(); // local tmp is a copy
   return tmp;                 // return by value (another copy)
}

обе формы эквивалентны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...