Инициировать ссылку на shared_ptr (std :: tr1 :: shared_ptr) - PullRequest
2 голосов
/ 16 декабря 2010

Я использую библиотеку, которая возвращает мне ссылку.
Мне нужно использовать эту ссылку в качестве атрибута класса.
Невозможно напрямую инициализировать атрибут в конструкторе (необходимо инициализировать библиотеку lib).до этого) я думал об использовании shared_ptr для отложенной инициализации:

#include <iostream>
#include <string>
#include <tr1/memory>

//This is library, cannot touch
std::string globalString = "TEST";
std::string& getStringReference()
{
    return globalString;
}

//this is my class which uses the library
class Foo
{
public:
    Foo() :
        testString_( std::tr1::shared_ptr< std::string& >() )
    {
        //do some initialization of the library here...
        //now init the shared_ptr
        testString_.reset( getStringReference() );
    }

    std::string getString() const
    {
        return *testString_;
    }

private:
    std::tr1::shared_ptr< std::string& > testString_;
};

//and a main to be compilable and check if the above works...
int main()
{
    Foo foo;
    std::cout << foo.getString() << std::endl;
}

Но, к сожалению, это не работает.g ++ выдает такие сообщения:

error: forming pointer to reference type ‘std::string&’

Я пробовал другие способы получить ссылку в shared_ptr, но ничего не работает ... Возможно, вы могли бы дать мне подсказку.

Примечание:
- В "реальном мире" вместо std :: string тип данных - это класс без конструктора по умолчанию.
- Для тех, кто все еще задается вопросом: приведенный выше пример представляет собой упрощенный пример кода:)

ОБНОВЛЕНИЕ:
- Пытаясь применить предложения, я обнаружил, что, в отличие от используемого std :: string из примера, у моего класса есть конструктор личных копий.Это означает, что я не могу просто скопировать объект в новый.

Ответы [ 7 ]

6 голосов
/ 16 декабря 2010

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

Хотя вы можете получить адрес реального объекта с помощью оператора &, это приведет к неопределенному поведению позже, когда ваш shared_ptr выйдет из области и попытается освободить память, а сама библиотека попытается освободить память сама по себе.

2 голосов
/ 16 декабря 2010

Вы просто не можете взять адрес ссылки.

Однако вы можете использовать shared_ptr<string> и инициализировать его с &getStringReference. Но это приведет к тому, что shared_ptr попытается удалить строку, что приведет к сбою, поскольку она никогда не выделялась с использованием new. Чтобы это исправить, сделайте копию:

testString_.reset(new std::string(getStringReference()))

Еще лучше, пусть ваш класс просто хранит ссылку напрямую. Вам совсем не нужно беспокоиться об управлении памятью:

class Foo
{
    std::string& _testString;

    // ...
}
1 голос
/ 16 декабря 2010

Вы должны понимать семантику ссылок и управления памятью.

То, что вы, вероятно, хотите, это необработанный указатель в вашем классе.Я предполагаю, что вы не можете использовать ссылку, потому что вы не знаете, на какой объект она будет ссылаться, пока не сделаете вызов функции, поэтому вы хотите сделать что-то вроде ref = getRef ();

У вас нет способа автоматически «защитить» указатель от «зависания», но не думайте, что вы можете что-то сделать, чтобы исправить эту ситуацию.Вам просто нужно посмотреть документацию о том, как правильно использовать ссылку / указатель.

1 голос
/ 16 декабря 2010

Прекратите использовать shared_ptr сейчас. Совместное использование не является односторонним решением.

При этом вам возвращается ссылка на объект, а не на сам объект. Вы можете сделать две вещи:

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

Я бы определенно рекомендовал копировать, если нет причин, чтобы сделать это намного проще.

Если вы собираетесь копировать, используйте boost::optional<LibObject> в своем классе, таким образом вы обойдете проблему инициализации.

Если вы хотите использовать ссылку, вы все равно можете использовать boost::optional, и она тоже будет работать! Используйте его так: boost::optional<LibObject&>, но убедитесь, что объект, на который вы ссылаетесь, будет жить достаточно долго.

Наконец, что касается проблемы инициализации, вы можете использовать функцию для обработки инициализации и возврата ссылки напрямую, таким образом инициализируя ссылку вашего класса в списке инициализации.

1 голос
/ 16 декабря 2010

Вы можете рассмотреть возможность использования Boost.Optional , который поддерживает необязательные ссылки .Таким образом, вы можете лениво инициализировать вашу ссылку, не вступая во владение ссылочным объектом, как вы делаете, используя shared_ptr:

#include <iostream>
#include <string>
#include <boost/optional.hpp>

//This is library, cannot touch
std::string globalString = "TEST";
std::string& getStringReference()
{
    return globalString;
}

//this is my class which uses the library
class Foo
{
public:
    Foo()
    {
        //do some initialization of the library here...
        //now init the optional reference
        testString_.reset( getStringReference() );
    }

    std::string getString() const
    {
        return *testString_;
    }

private:
    boost::optional< std::string& > testString_; //<-- note the use of optional
};

//and a main to be compilable and check if the above works...
int main()
{
    Foo foo;
    std::cout << foo.getString() << std::endl;
}
0 голосов
/ 16 декабря 2010

Использовать заводскую функцию?

class Library
{ 
 public:
  static void Init();
  static LibraryThing & getThing();
};


class Foo
{
  public:
  static shared_ptr<Foo> Create()
  {
   if (!_libInit)
   {
    Library::Init();
    _libInit = true;
   }
   return make_shared(new Foo(Library::getThing()));
  }

 private:
  Foo(LibraryThing & ref) : _ref(ref)
  {
  }

 private:
  LibraryThing & _ref;
  static bool     _libInit;
};
0 голосов
/ 16 декабря 2010

Нельзя использовать shared_ptr со ссылочным типом, потому что ссылка - это просто ссылка на объект.Это не настоящий объект.

Следующий пример - просто упрощенная версия того, что вы пытались сделать:

int main()
{
  int &* a;
}
...