2016-03-28 1 views
1

J'écris du code basé sur le pointeur intelligent de problème 28 de C++ plus efficace comme suit. Cependant, il ne peut pas compiler:Initialisation invalide de la référence de type non-const à partir d'une valeur de type

main.cpp: In instantiation of 'SmartPointer<T>::operator SmartPointer<U>() [with U = MusicProduct; T = Cassette]': 
main.cpp:99:17: required from here 
main.cpp:48:39: error: invalid initialization of non-const reference of type 'SmartPointer<MusicProduct>&' from an rvalue of type 'SmartPointer<MusicProduct>' 
     return SmartPointer<U> (ptr_); 
           ^
main.cpp:16:9: note: initializing argument 1 of 'SmartPointer<T>::SmartPointer(SmartPointer<T>&) [with T = MusicProduct]' 
    SmartPointer(SmartPointer<T>& other) 
    ^

Chacune de ces deux changements fonctionne:

  1. dans la mise en œuvre de l'opérateur pointeur intelligent(), créer un objet et retour:

    pointeur intelligent un (ptr_)

    retour a;

  2. Ou, faire le paramètre du constructeur de copie const

    pointeur intelligent (const & autre pointeur intelligent)

    et commenter la ligne

    other.ptr_ = nullptr;

Y a-t-il une raison pour laquelle l'une des solutions fonctionne? Merci.


#include <iostream> 

template <typename T> 
class SmartPointer 
{ 
    public: 
    SmartPointer(T* ptr) : ptr_(ptr) {} 
    ~SmartPointer() 
    { 
     if (ptr_) 
     { 
     delete ptr_; 
     } 
    } 

    SmartPointer(SmartPointer<T>& other) 
    { 
     ptr_ = other.ptr_; 
     other.ptr_ = nullptr; 
    } 

    SmartPointer<T>& operator = (SmartPointer<T>& other) 
    { 
     if (this == &other) 
     { 
     return *this; 
     } 

     if (ptr_) 
     { 
     delete ptr_; 
     } 

     ptr_ = other.ptr_; 
     other.ptr_ = nullptr; 

     return *this; 
    } 

    template <typename U> 
    operator SmartPointer<U>() 
    { 
     // it works 
     //SmartPointer<U> a(ptr_); 
     //return a; 

     // error 
     return SmartPointer<U> (ptr_); 
    } 

    T& operator *() const 
    { 
     return *ptr_; 
    } 

    T* operator ->() const 
    { 
     return ptr_; 
    } 

    private: 
    T* ptr_ = nullptr; 
}; 

class MusicProduct 
{ 
public: 
    MusicProduct(const std::string& name) : name_(name) {} 
    virtual ~MusicProduct() {} 

    virtual void Play() const = 0; 
    virtual void ShowName() const 
    { 
    std::cout << name_ << std::endl; 
    } 

private: 
    std::string name_; 
}; 
class Cassette : public MusicProduct 
{ 
    public: 
    Cassette(const std::string& name) : MusicProduct(name) {} 
    void Play() const 
    { 
    std::cout << "play cassette" << std::endl; 
    } 
}; 

void CallPlay(const SmartPointer<MusicProduct>& sp) 
{ 
    sp->Play(); 
} 

int main() 
{ 
    SmartPointer<Cassette> a(new Cassette("Zhang")); 
    a->ShowName(); 
    CallPlay(a); 
    return 0; 
} 

Répondre

2

C'est parce que votre ctor copie a un paramètre de référence non const et ne peut donc pas accepter temporaire. Ainsi

return SmartPointer<X>(y); 

ne fonctionnera pas. L'argument du mot-clé return est temporaire, et il doit être copié, donc ici la conception se décompose.

Puisque vous utilisez C++ 11, vous pouvez corriger cela en introduisant un constructeur de déplacement (et une affectation de déplacement).

Vous pouvez également créer l'argument const et désigner le membre ptr_ comme mutable. Cela vous permettra de copier des pointeurs temporaires et const, mais pour le prix de les muter réellement.

+0

Merci. Lorsque vous créez un objet SmartPointer a (ptr_) et renvoyez a, la variable a n'est pas temporaire, bien que ce ne soit qu'une variable locale dans cette fonction? – kwunlyou

+1

Les variables nommées ne sont pas temporaires. –