2016-03-28 6 views
1

Я пишу некоторый код на основе интеллектуального указателя 28-й проблемы более эффективного C++ следующим образом. Тем не менее, он не может скомпилировать:Недействительная инициализация неконстантной ссылки типа из rvalue типа

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

Любая из этих двух изменений работает:

  1. в реализации оператора умный указатель(), создать объект и вернуть:

    умный указатель на (ptr_);

    возвращение a;

  2. Или сделать параметр конструктора копии константным

    умный указатель (Const & другой умный указатель)

    и комментарии линии

    other.ptr_ = nullptr;

Есть ли причина, почему любое из решений работает? Благодарю.


#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; 
} 

ответ

2

Это потому, что ваша копия имеет т е р неконстантную ссылочный параметр и, следовательно, не может принять временное. Таким образом,

return SmartPointer<X>(y); 

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

Поскольку вы используете C++ 11, вы можете исправить это, введя конструктор перемещения (и переместите назначение).

Вы также можете внести аргумент const и указать ptr_ член как mutable. Это позволит вам копировать из временных и const интеллектуальных указателей, но по цене фактического их изменения.

+0

Спасибо. Когда создается объект SmartPointer a (ptr_) и возвращает a, переменная a не является временной, хотя это только локальная переменная в этой функции? – kwunlyou

+1

Именованные переменные не являются временными. –

Смежные вопросы