【问题标题】:C++ universal data typeC++ 通用数据类型
【发布时间】:2010-03-31 19:24:39
【问题描述】:

我有一个通用数据类型,它是按值传递的,但不维护类型信息。我们只在其中存储指针和基本数据类型(如 int、float 等)。现在第一次,我们需要在其中存储 std::string 。所以我们决定把它转换成 std​​::string* 并存储起来。然后是破坏的问题。我们不喜欢每次都复制 std::string。所以我正在考虑这样的方法。假设数据类型是这样的

class Atom
{
public :
     enum flags
     {
         IS_STRING,
         IS_EMPTY,
         HAS_GOT_COPIED,

         MARKER
     };

private:
     void*   m_value;
     std::bitset<MARKER>   m_flags;

public:
    .....
    Atom( Atom& atm )
    {
        atm.m_flags.set( HAS_GOT_COPIED );
        ..... 
    }
    .....
    ~Atom()
    {
        if( m_flags.test(IS_STRING) && !m_flags.test(HAS_GOT_COPIED) )
        {
             std::string*  val = static_cast<std::string*>(m_value);
             delete val;
        }
    }
};

这是找出是否不再引用 std::string* 的好方法吗?任何cmets..

我看过 boost::any 和 poco::DynamicAny。由于我需要序列化,所以我不能使用这些。

谢谢, 悟空。

【问题讨论】:

  • 你看过 boost::variant 吗?序列化如何影响 boost::any 的使用? (我从未尝试过 poco::DynamicAny)
  • 为什么不在 Atom 将包含的对象类型上模板化?
  • @George:这不是一种数据类型,也不能达到目的。

标签: c++


【解决方案1】:

这种方法的一个主要缺陷是您确实需要一个引用计数,而不是一个“已被复制”标志。如果您多次复制字符串,该位将不起作用。如前所述,如果您创建 Atom 的副本并在原始副本之前删除副本,则会遇到麻烦:

Atom a("hello world");

if (...) {
    Atom b(a);
    // b is destroyed, deleting the string
}

// Uh oh, the string's been deleted but a is still referencing it.
cout << (string) a;

我不会重新发明轮子。如果 boost::any 不能开箱即用,您仍然可以在内部使用它来代替您的 m_value 字段来存储您的 Atom 类的数据。这将为您处理所有构建/复制/销毁细节。

【讨论】:

  • 谢谢.. 我有这个问题。但我无法使用 boost::any 因为它不支持 boost 序列化
  • 您可以将序列化添加到您的类中(正如您现在所做的那样)并在内部使用 boost::any 或 boost::variant
  • @David:我不想支付 boost::any 的成本,如果我不能存储 type_info( 通过将所有内容转换为 void* 然后将其放入 boost::any 中)。目前我正在通过将数据作为字节流进行序列化,长度为。
  • 你怎么知道你必须如何解释反序列化的元素?使用 boost::any 方法(内存、序列化信息)无法支付的成本是多少?
  • @David: boost::any 对每个数据提取、每个复制构造函数调用、每个析构函数调用都有虚函数调用,即使是简单的数据类型也涉及动态分配
【解决方案2】:

我认为您应该研究使用 boost::shared_ptr(或 std::tr1::shared_ptr)的可能性。

【讨论】:

  • 这是按值传递的数据类型。我认为您的建议对于通过引用数据类型传递是有效的。
  • 他的建议适用于可复制的按值传递的类。显然,不可复制的按引用传递类型没有复制问题。
  • 我的意思是使用 shared_ptr 来跟踪 std::string* 并在正确的时刻释放。您的代码将如何处理包含 std::string 的 Atom 已被复制多次且原始实例具有最长生命周期的情况?
  • 我只需要确保在没有引用时数据将被删除。
  • @Andres:: 当我有按值传递数据类型时会发生这种情况吗?通常它会从一个函数传递到另一个函数并通过赋值复制。
【解决方案3】:

您可能希望将“写入时复制”输入谷歌并阅读该主题。它通常是如何实现的,它的用途是什么,它的缺点是什么。

你看过boost::any吗?

【讨论】:

  • 是的,我查看了 boost::any。这里不能使用它,因为我们需要对它进行序列化。
  • @Gokul:这并不是说您的类型会免费提供序列化 - 您也必须自己实现。如果你的基础是boost:any,至少你有一个坚实的基础。
【解决方案4】:

我在第一份工作中的首要任务之一是设计一个变体类。您可以在 comp.lang.c++.moderated post 中找到一些基本代码(和讨论)。

由于您还需要序列化,您可能对JsonCpp 库感兴趣。我认为它提供了您正在寻找的东西:可以是字符串、布尔值、整数、数组、对象等的数据类型......(Json::Value 类。)

【讨论】:

  • 陌生人,请在你投反对票时解释一下:)
【解决方案5】:

除了这种“通用数据类型”是否是一个好主意之外,如果你不复制字符串,这个类能否确定它拥有它所指向的字符串?你能保证只有通过new 分配的字符串才会被传递给类以获得所有权吗?

这个类的设计看起来好像会有问题。

【讨论】:

  • 是的,我只有那个构造函数,没有设置语句。
  • @Gokul - 这不是真正的问题。您能否确定调用构造函数的人只会使用通过new 分配的字符串来执行此操作,并且调用者随后不会在该字符串上调用delete?这些规则很难在您的设计中强制执行,因此在提交此类设计之前考虑它们可能是个好主意。
  • 对不起,我没有提到它,但人们只会将它作为 std::string 传递,我会将它转换为 std::string* 里面的。所以我需要释放它。如果它作为 std::string* 传递,那么这不会担心释放它。
猜你喜欢
  • 2018-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多