Domanda

Sto cercando di creare un tipo immutabile (classe) in C ++,

L'ho fatto in modo che tutti i metodi "alias funzioni membro" non modificare l'oggetto e restituire invece una nuova istanza.

Sto riscontrando diversi problemi, ma ruotano tutti attorno ai tipi di riferimento in C ++.

Un esempio è quando si passano parametri dello stesso tipo di classe per riferimento:

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

L'errore è causato dal passaggio del valore per riferimento. Se invece passassi il riferimento in base al valore, la riga di errore sopra riportata non sarebbe un errore!

Prendi in considerazione un esempio 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
        ....  
    }
    ....
}

Come posso fare qualcosa del genere in C ++? So che posso usare i puntatori ma poi mi imbatto in tutto il pasticcio di gestione della memoria. Non voglio preoccuparmi di chi possiede riferimenti agli oggetti.

Idealmente, vorrei progettare la classe in modo che diventasse come stringhe immutabili in Python; puoi usarli senza mai accorgerti o nemmeno sapere che sono immutabili e si comportano come ti aspetti; funzionano e basta.

Modifica

Ovviamente posso aggirarlo passando per valore o usando una variabile temp (che è quello che sto facendo attualmente). Quello che sto chiedendo è "come passare i riferimenti in base al valore in C ++"

Mi aspetto che la risposta ruoti intorno a qualcosa nella STL, sto attualmente esaminando la famiglia di modelli smart_ptr.

Aggiorna

Grazie per le risposte, mi rendo conto che non c'è scampo dai puntatori. (vedi la mia altra domanda , che è davvero un seguito su questo)

È stato utile?

Soluzione

In Java e C #, in realtà non hai a che fare con un riferimento: sono più simili a handle o puntatori. Un riferimento in C ++ è in realtà un altro nome per l'oggetto originale, non un puntatore ad esso (sebbene possa essere implementato con un puntatore). Quando si assegna un valore a un riferimento, si assegna all'oggetto stesso. C'è confusione in quanto per inizializzare un riferimento è possibile utilizzare il carattere = , ma si tratta di un'inizializzazione, non di un compito.

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

Se desideri passare in modo specifico "riferimenti per valore" allora stai essenzialmente chiedendo una contraddizione in termini. I riferimenti, per definizione, vengono passati per riferimento. Come indicato altrove, è possibile passare un puntatore per valore, oppure un valore semplice. Se vuoi davvero, puoi mantenere un riferimento in una classe e passarlo per valore:

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

Nota anche che una const applicata a un riferimento sta rendendo costante l'oggetto riferito, non il riferimento. I riferimenti sono sempre cost.

Altri suggerimenti

L'assegnazione, per definizione, non è un'operazione costante?

Sembra che tu stia cercando di assegnare qualcosa a un riferimento const, che sconfigge totalmente l'idea di un riferimento const.

Penso che potresti cercare un puntatore anziché un riferimento.

Non funziona così in C ++.

Quando si passa un riferimento a un oggetto, in realtà si passa l'indirizzo in memoria dell'oggetto. Neanche i riferimenti possono essere riposizionati su altri oggetti, quindi l'adagio C ++ "il riferimento È l'oggetto." DEVI fare una copia per modificarlo. Java lo farà dietro le quinte per te. C ++, devi solo copiarlo.

Non hai dimenticato di impostare il metodo che chiami const?

EDIT: quindi, con const fissa.

Forse dovresti fare qualcosa del genere

Imm & tmp = p_im.someOtherOp();

Quindi esegui ulteriori operazioni sulla variabile tmp.

Se imposti una variabile o un parametro come const & amp; non puoi assegnarglielo.

Controlla questo per conoscere la durata temporanea 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
   ...
}

Ma puoi usare 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();
}

Devi creare una nuova copia del tuo argomento in arrivo. Puoi fare quello che vuoi in diversi modi equivalenti: 1) potresti passare per valore:

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

o 2) puoi passare per riferimento ed effettuare una copia esplicitamente:

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

entrambi i moduli sono equivalenti.

C ++ ha qualcosa di meglio dei tipi immutabili & # 8212; const . Un singolo tipo può essere modificabile o meno a seconda delle tue esigenze. Detto questo, ci sono modelli utili per gestire copie di breve durata (quasi):

void f(const X &x) {
  // Trivial case: unconditional copy
  X x2=transform(x);
  // Less trivial: conditional copy
  std::optional<X> maybe;
  const X &use=need_copy ? maybe.emplace(transform(x)) : x;
  use.go();  // whichever, x or *maybe
}  // *maybe destroyed iff created, then x2 destroyed

std :: unique_ptr può essere usato in modo simile prima di C ++ 17, anche se la funzione può ovviamente lanciare std :: bad_alloc .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top