初始化一个shared_ptr引用(std :: tr1 :: shared_ptr <class&>)</class&>

时间:2010-12-16 09:03:54

标签: c++ reference shared-ptr

我正在使用一个库来返回对我的引用 我需要将此引用用作class-attribute 无法直接在构造函数中初始化属性(之前需要使用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 个答案:

答案 0 :(得分:6)

如果仅由参考提供,则表示您不对内存管理负责,而这反过来意味着您无法使用您自己的内存管理。也就是说,您不应该使用任何类型的智能指针来保存该对象。

虽然您可以使用&运算符获取实际对象的地址,但是当shared_ptr超出范围并尝试释放内存和库时,这样做会导致未定义的行为本身试图释放它自己的记忆。

答案 1 :(得分:2)

您根本无法获取参考地址。

但是,您可以使用shared_ptr<string>并使用&getStringReference对其进行初始化。但这会导致shared_ptr尝试删除字符串,导致它失败,因为它从未使用new分配。要解决此问题,请复制一份:

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

更好的是,让您的班级直接存储参考。你根本不需要打扰内存管理:

class Foo
{
    std::string& _testString;

    // ...
}

答案 2 :(得分:1)

您可以考虑使用支持Boost.Optionaloptional references。这样,您可以延迟初始化引用,而不像使用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;
}

答案 3 :(得分:1)

立即停止使用shared_ptr。分享不是单方面的决定。

话虽如此,您将返回对对象的引用,而不是对象的引用。你可以做两件事:

  • 复制对象,因此决定自己管理副本的生命周期
  • 引用该对象,并将其调用到您调用的库以管理生命周期,在这种情况下,您需要了解它的相关知识

我绝对会建议复制,除非有理由不这样做,更容易做到正确。

如果您要复制,请在班级中使用boost::optional<LibObject>,这样您就可以绕过初始化问题。

如果您希望使用引用,您仍然可以使用boost::optional,它也可以使用!使用它:boost::optional<LibObject&>,但请确保您引用的对象将存活足够长。

最后,关于初始化问题,您可以使用函数来处理初始化并直接返回引用,从而在初始化列表中初始化类的引用。

答案 4 :(得分:1)

您需要了解引用和内存管理的语义。

您可能想要的是您班级中的原始指针。我假设你不能使用引用,因为你不知道它将引用什么对象,直到你进行函数调用,所以你想做一些像ref = getRef();

你无法自动“保护”你的指针而不是“晃来晃去”,但不要认为你可以采取任何措施来纠正这种情况。您只需要查看有关如何正确使用引用/指针的文档。

答案 5 :(得分:0)

您不能将shared_ptr与引用类型一起使用,因为引用就是 - 对对象的引用。这不是一个真实的对象。

下一个示例只是您尝试执行的操作的简化版本:

int main()
{
  int &* a;
}

答案 6 :(得分:0)

使用工厂功能?

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