Search code examples
c++referenceconstantsimmutability

How to pass references by value in C++?


I'm trying to create am immutable type (class) in C++,

I made it so that all methods "aka member functions" don't modify the object and return a new instance instead.

I'm running across a bunch of issues, but they all revolve around the reference types in C++.

One example is when passing parameters of the same class type by reference:

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

The error is caused by passing the value by reference. If instead, I was passing the reference by value, then the error line above would not be an error!

Consider a Java/C# example

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
        ....  
    }
    ....
}

How can I do something like this in C++? I know I can use pointers but then I run into the whole memory management mess. I don't want to worry about who owns references to objects.

Ideally I'd like to design the class to be like immutable strings in python; you can use them without ever noticing or even knowing that they're immutable, and they just behave as you expect; they just work.

EDIT

Of course I can get around it by passing-by-value or by using a temp variable (which is what I'm doing currently). What I'm asking about is "how to pass references by value in C++"

I'm expecting the answer to revolve around something in the STL, I'm currently looking into smart_ptr family of templates.

UPDATE

Thanks for the responses, I realize there's no escape from pointers. (see my other question, which is really a follow up on this one)


Solution

  • In Java and C#, you are not really dealing with a reference - they are more like handles or pointers. A reference in C++ is really another name for the original object, not a pointer to it (although it may be implemented with a pointer). When you assign a value to a reference, you are assigning to the object itself. There is confusion in that to initialize a reference you can use the = character, but it is an initialization, not an assignment.

     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).
    

    If you specifically want to pass "references by value" then you are essentially asking for a contradition in terms. References, by definition are passed by reference. As pointed out elsewhere, you can pass a pointer by value, or else a straight value. If you really want, you can hold onto a reference in a class and pass that around by value:

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

    Note also that a const applied to a reference is making the referred to object constant, not the reference. References are always const.