【问题标题】:Copying local object to vector将本地对象复制到向量
【发布时间】:2014-08-23 16:02:59
【问题描述】:

我有一个包含数据向量的单例类。我的问题是我想使用标准的 push_back() 方法向该向量添加数据。我有一个要保存在该向量中的对象,但它是一个本地对象(在另一个类的方法中创建)。显然,在此方法结束时,局部变量将被删除,这很好,因为我对该向量执行了 push_back()。

现在,只要方法没有结束,它就可以正常工作。结束后数据就没有了。这看起来很奇怪,因为 push_back() 应该使用复制构造函数对吗?现在,我尝试通过引用、值、指针和 C++11 中的移动构造函数将局部变量添加到向量中,但所有这些似乎都不起作用。

所以这是问题类的设置:

  • ConnectionManager(保存向量)
  • ClassA(具有本地 typeX 对象的方法)

所以,简而言之,我希望在 ClassA 中的方法中创建的对象在该方法之后可用,但在 ConnectionManager 类的向量中。

编辑:这是我所说的 typeX:

struct Connection
{
    SOCKET socket;
    PlayerData* pPlayerData;
};

socket 只是普通的 winsock SOCKET 变量,PlayerData* 是使用 Google 的 ProtocolBuffer 创建的自定义对象。

进一步编辑:

这就是我创建数据的方式:

Predefined::Connection connTemp;
connTemp.socket = 0;
connTemp.pPlayerData = data;
MultiplayerData::GetInstance()->AddPlayerToGame(connTemp);

connTemp.pPlayerData,回答这个问题,是一个本地创建的变量,但它是作为指针创建的。

【问题讨论】:

  • 你能告诉我们problematic类型typeX吗?
  • 我把它添加到主要问题中
  • pPlayerData 是否指向局部变量?
  • 谁管理PlayerData 的生命周期?
  • 你在应用三/五规则吗?

标签: c++ c++11 vector


【解决方案1】:

如果问题是您正在创建 PlayerData 数据,并且希望在函数退出后仍然可以使用相同的数据,那么您应该使用诸如 std::shared_ptr<PlayerData> 之类的类型而不是裸PlayerData*.

#include <vector>
#include <memory>
//..
class PlayerData 
{
   int x, y, z;
   public:
     PlayerData(int a1, int a2, int a3) : x(a1), y(a2), z(a3) {}
};

typedef std::shared_ptr<PlayerData> PlayerDataPtr;

struct Connection
{
    SOCKET socket;
    PlayerDataPtr pPlayerData;
};

typedef std::vector<Connection> ConnectionVector;

void foo()
{
   auto data = std::make_shared<PlayerData>(1, 2, 3);  // create data dynamically
   //...
   Connection connTemp;
   connTemp.socket = 0;
   connTemp.pPlayerData = data;
   MultiplayerData::GetInstance()->AddPlayerToGame(connTemp);  // this does the push_back
   //...
}  

由于pPlayerData 现在是shared_ptrvector 生成的那些副本只会增加引用计数,相反,当这些副本被销毁时,引用计数会减少。当引用计数达到 0 时,data 确实会被删除。

如果你没有在共享指针上调用reset,这或多或少,你保证在push_back完成之前创建的data将存在,只要向量中的那个条目没有被删除。

此外,我编辑了示例以显示更简单的 PlayerData 类。注意make_shared 的使用方式。

【讨论】:

  • 您好,感谢您的代码。我试过了,但在这一行出现错误:auto data = std::make_shared&lt;PlayerData&gt;(message.add_playerdata()); 它说:'PlayerData::PlayerData(const PlayerData &amp;)' : cannot convert parameter 1 from 'PlayerData *' to 'const PlayerData &amp;'
  • @Dries - 您需要显示message.add_playerdata() 返回的内容。其次,make_shared 的参数是构造PlayerData 所需的参数。所以你说要构造一个PlayerData,你需要将一个指针传递给PlayerData?这听起来令人困惑,并且可能是您丢失数据的原因。看看我上面编辑的代码。
  • 问题是我需要调用message.add_playerdata(),因为它是由ProtocolBuffer 生成的。它返回一个PlayerData*。该返回值被添加到auto data 中,显然它可以被填充。这就是 ProtocolBuffer 的工作原理。我在message.add_playerdata() 前面添加了一个*,现在它可以编译了。我会让你知道它的作用。编辑:好吧,那没有用
  • 我将行更改为:shared_ptr&lt;PlayerData&gt; data(message.add_playerdata());,但在将其添加到向量并且方法结束后,它仍然会丢失其中的数据。另外,单例也没有问题,我检查了它的值,并且在所有地方都一样
  • 肯定是struct中的PlayerData对象有问题,因为socket值存储正确
【解决方案2】:

结构连接确实会被复制到向量中,因此您不必担心它的生命周期结束。但是 pPlayerData 需要指向分配给 new 并归某人所有的内存。

connTemp.pPlayerData = data;

“数据”从何而来 - 本地生成? 'data' 需要在某些时候由'new' 分配。

如果“数据”都是唯一的,请考虑对 pPlayerData 成员的类型使用 auto_ptr 或 unique_ptr - C++ 不会自动管理标准指针。如果它们不是唯一的,请使用 shared_ptr 或 intrusive_ptr - 可以从 shared_ptr 开始,然后再改进 intrusive。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 2010-10-20
    • 1970-01-01
    • 2019-07-14
    • 1970-01-01
    相关资源
    最近更新 更多