2017-02-08 8 views
3

Я отношусь к C++ с новым релятивизмом, и этот шов, как вопрос о нобе, но я не смог его решить с помощью других ресурсов в Интернете.Создайте shared_ptr со ссылкой

Я пытаюсь создать shared_ptr из ссылки. У меня следующий Book класс:

#include <memory> 
#include "Author.hpp" 

class Book 
{ 
    public: 
     void setAuthor(const Author& t_author); 

    private: 
     std::shared_ptr<Author> m_author; 
} 

И это мой Author класс:

#include <memory> 
class Book; 

class Author 
{ 
    public: 
     void addBook(const Book& t_book); 

    private: 
     std::vector<std::weak_ptr<Book>> m_books; 
} 

Я устал реализовать метод Book::setAuthor следующим образом:

void Book::setAuthor(const Author& t_author) 
{ 
    m_author = std::shared_ptr<Author>(&t_author); 
} 

Но если я пытаюсь скомпилировать это я получаю:

Invalide преобразование сопзЬ Автор * до * Автор

Invalide преобразование из SizeOf в сопзЬ Автор

Можете ли вы сказать мне, что случилось с моим кодом? Я также пробовал то же самое со слабым_ptr, но это тоже не работает.

+0

Я думаю, вы должны использовать 'std :: vector ' и 'std :: vector '. Нет указателя, нет 'std :: shared_ptr', no' std :: weak_ptr'. Управлять отношениями между книгами и авторами в ** реляционной базе данных **; для чего они нужны. Рассматривайте объекты 'std :: vector ' и 'std :: vector ' как временно необходимые результаты запросов к базе данных. –

+0

@ChristianHackl Вы правы, и я также хочу этого, но я хотел бы использовать библиотеку ORM (http://www.codesynthesis.com/products/odb/), и там я должен использовать 'vectors'' shared_ptr 'для представления отношений [от одного до многих] (http://www.codesynthesis.com/products/odb/doc/manual.xhtml#6.2.2). Или есть другой способ сделать это? – Cilenco

+0

@Cilencio: Ну, зачем использовать библиотеку, если она заставляет вас использовать испорченный дизайн? ORM не является самоцелью. –

ответ

5

Хотя, ваша ошибка связана с тем, что std::shared_ptr<Author> конструктор используется ожидает Author*, но результаты выражение &t_author на объект типа const Author*


Еще не то:

void Book::setAuthor(const Author& t_author) 
{ 
    m_author = std::shared_ptr<Author>(&t_author); 
} 

Представьте, что вы звоните book.setAuthor(Author("Herb Sutter"));, у вас будет болтающийся указатель, потому что t_author прекратит чтобы существовать после завершения этой функции.


Вам нужно скопировать или переместить объект в свой std::shared_ptr экземпляр. Используйте std::make_shared<T>, чтобы создать свои std::shared_ptr<T> объекты по возможности.

void Book::setAuthor(const Author& t_author) 
{ 
    m_author = std::make_shared<Author>(t_author); 
} 

еще лучше:

void Book::setAuthor(Author t_author) 
{ 
    m_author = std::make_shared<Author>(std::move(t_author)); 
} 
+0

Спасибо за ответ, который мне очень помог. Не могли бы вы посмотреть мой комментарий ниже вопроса? Как вы думаете, что будет лучшим шаблоном проектирования для подхода «один ко многим»? Или я не должен использовать такую ​​библиотеку ORM? – Cilenco

+0

@Cilenco: * «Должен ли я использовать библиотеку ORM?» * - это очень широкий и основанный на мнениях вопрос! :) Я думаю, что единственный ответ, который мы можем вам дать, - это выбрать правильный инструмент для требований вашего программного обеспечения (или вашего работодателя), никогда не использовать инструмент, чтобы вы могли использовать инструмент, и имейте в виду, что каждое решение имеет преимущества и обязательства. Кто знает, даже сам C++ может быть плохим выбором для этой конкретной проблемы, но мы не можем сказать, не понимая проблемы. –

3

Если вы хотите сделать копию с помощью std::make_shared:

void Book::setAuthor(const Author& t_author) 
{ 
    m_author = std::make_shared<Author>(t_author); 
} 

, но это неправильный дизайн, если вы ожидаете, чтобы сохранить право собственности, переданных объектов вы должны передать std::shared_ptr своей функции вместо ссылки на константу:

void Book::setAuthor(std::shared_ptr<Author> t_author) 
{ 
    m_author = std::move(t_author); 
} 
+0

Итак, с моим дизайном я больше не буду владельцем ссылки? Не могли бы вы объяснить это более подробно? У вас также есть идеи для хорошего шаблона дизайна с библиотекой odb (orm) (см. Комментарии по этому вопросу). – Cilenco

+0

В вашем проекте вы передаете объект по ссылке const, поэтому вы можете вызвать его методы const или сделать копию. В вашем классе вы используете 'std :: shared_ptr', который предлагает совместное владение. Что-то не так, здесь вы не должны использовать 'std :: shared_ptr' или передавать объекты, которые уже принадлежат' std :: shared_ptr' для вашего класса, чтобы иметь возможность делиться. – Slava

+0

И нет такой вещи, как владелец ссылки. Если вы передаете объект по ссылке, вы предполагаете, что функция, которую вы передаете, не может взять на себя или передать права собственности на нее. – Slava

2

Возможно, это неопределенное поведение. shared_ptr указывает собственность объекта, на который указывает. Почти во всех возможных сценариях t_author относится к существующему Author, которому принадлежит что-то еще. Почти наверняка будет два места, которые пытаются уничтожить экземпляр.

Если вы должны создать shared_ptr к существующему примеру, вы можете посмотреть в использовании enable_shared_from_this, но это работает только если t_author была создана с std::make_shared. И если это так, вы можете также изменить свою функцию, чтобы принять shared_ptr напрямую. Кроме того, вы можете создать shared_ptr с пользовательским удалением, который ничего не делает. Но в этот момент вам нечего выиграть от использования shared_ptr, за исключением, возможно, совместимости с некоторым интерфейсом.

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