C++ 初始化一个共享的引用(std::tr1::shared_ptr<;class>;)

C++ 初始化一个共享的引用(std::tr1::shared_ptr<;class>;),c++,reference,shared-ptr,C++,Reference,Shared Ptr,我正在使用一个向我返回引用的库。 我需要将此引用用作类属性。 由于无法直接初始化构造函数中的属性(lib需要在之前初始化),我考虑使用共享的_ptr进行延迟初始化: #include <iostream> #include <string> #include <tr1/memory> //This is library, cannot touch std::string globalString = "TEST"; std::string& getS

我正在使用一个向我返回引用的库。
我需要将此引用用作类属性。
由于无法直接初始化构造函数中的属性(lib需要在之前初始化),我考虑使用共享的_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;
}
我尝试了其他一些方法来将引用导入共享的\u ptr,但没有任何效果。。。也许你能给我一个暗示

注:
-在“真实世界”中,数据类型不是std::string,而是没有默认构造函数的类。
-对于那些仍然好奇的人:上面只是一个简化的示例代码:)

更新:

-在尝试应用这些建议时,我发现与示例中使用的std::string相反,我的类有一个私有副本构造函数。这意味着我无法将对象复制到新对象中。

您无法获取引用的地址

但是,您可以使用
shared\u ptr
并使用
和getStringReference
对其进行初始化。但这将导致共享的_ptr尝试删除该字符串,导致该字符串失败,因为它从未使用new进行分配。要解决此问题,请复制一份:

testString_.reset(new std::string(getStringReference()))
更好的是,让您的类直接存储引用。您根本不需要担心内存管理:

class Foo
{
    std::string& _testString;

    // ...
}

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

当您可以使用<代码>和/代码>运算符获取真实对象的地址时,这样做会在以后的“代码”> SydDypTr>/Cult>超出范围并试图释放内存,而库本身试图释放它自己的内存时会导致未定义的行为。

您可以考虑使用,哪种支持。通过这种方式,您可以像使用

shared\u 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;
}
#包括
#包括
#包括
//这是图书馆,不能碰
std::string globalString=“TEST”;
std::string&getStringReference()
{
返回全局字符串;
}
//这是我使用图书馆的班级
福班
{
公众:
Foo()
{
//在这里对库进行一些初始化。。。
//现在初始化可选引用
testString.reset(getStringReference());
}
std::string getString()常量
{
return*testString;
}
私人:

boost::optionaltestString\u;//您不能将共享的\u ptr与引用类型一起使用,因为引用只是对对象的引用。它不是真正的对象

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

int main()
{
  int &* a;
}

现在停止使用
shared\u ptr
。共享不是单方面的决定

也就是说,返回的是对对象的引用,而不是对象本身。您可以做两件事:

  • 复制对象,从而决定自己管理复制的生存期
  • 获取对该对象的引用,并将其添加到为管理生命周期而调用的库中,在这种情况下,您需要对其有一些了解
我肯定会建议复制,除非有理由不这样做,否则更容易做到正确

如果要进行复制,请在类中使用
boost::optional
,这样可以绕过初始化问题

如果您希望使用引用,您仍然可以使用
boost::optional
,它也会起作用!请这样使用:
boost::optional
,但请确保有引用的对象将足够长


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

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

您可能需要的是类中的原始指针。我假设您不能使用引用,因为在进行函数调用之前,您不知道它将引用什么对象,所以您希望执行类似ref=getRef()的操作


您无法自动“保护”您的指针,使其不会“悬空”,但您不认为可以采取任何措施来纠正这种情况。您只需查看文档,了解如何正确使用引用/指针。

使用工厂函数

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;
};
类库
{ 
公众:
静态void Init();
静态LibraryThing&Getting();
};
福班
{
公众:
静态共享\u ptr Create()
{
if(!\u libInit)
{
库::Init();
_libInit=true;
}
返回make_shared(newfoo(Library::getThing());
}
私人:
Foo(图书馆用品和参考资料):\u-ref(参考资料)
{
}
私人:
图书馆用品和参考;
静态bool_libInit;
};

如果没有可选项,我看不出代码会有什么不同。除了额外的复杂性。顺便说一句,您忘记在构造函数的初始化列表中初始化testString。@VJo:如果没有可选项,则需要在构造函数的初始化列表中初始化引用(此处不可能,因为在获取引用之前需要初始化库)。并且在初始化列表中不需要初始化
testString\uuuu
,默认构造正是我们需要的。好的,应该有另一个方法来初始化该变量,并且在构造函数中它应该是未初始化的。你是对的,我错过了这一点(如果该解决方案可行,我会在以后的长时间调试过程中自己发现)感谢上一个解决方案(简单地使用引用作为属性)的问题是,我必须在构造时初始化该属性。但是我不能这样做,因为库需要
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;
};