在std :: vector声明中使用void指针有多糟糕?

时间:2010-10-21 12:39:13

标签: c++ vector void

我有两个不同的课程如下:

class text
{ };

class element
{ };

我希望将它们存储在class node

template <typename T>
class node
{
    T cargo;

    std::vector<void*> children;

    node(T cargo) : cargo(cargo)
    { };

    void add_child(T node)
    {
        this->children.push_back((void*) node);
    }
}

所以我会以这种方式调用节点,同时存储textelement

element div;
text msg;

node<element> wrapper(div);

wrapper.add_child(msg);

编辑:要取回我使用T typedef type;的内容并将空指针转换为(type*)

我知道这不是很优雅也不实用,但我无法弄清楚这样做的正确方法是什么。所以请告诉我这是否实际可以接受,如果不是,那么如何以适当的方式做到这一点。

提前致谢!

6 个答案:

答案 0 :(得分:6)

#include <vector>
using namespace std;

class Element {};
class Text {};
class Nothing {};

class Node
{
private:
    vector< Node* >     children_;
protected:
    Node() {}
public:
    void add( Node* p ) { children_.push_back( p ); }
    virtual ~Node() {}
};

template< class Cargo >
class CargoNode
    : public Node
{
private:
    Cargo   cargo_;
public:
    CargoNode(): cargo_() {}
};

typedef CargoNode< Element >    ElementNode;
typedef CargoNode< Text >       TextNode;
typedef CargoNode< Nothing >    RootNode;

int main()
{
    RootNode*   root    = new RootNode;

    root->add( new ElementNode );
    root->add( new ElementNode );
    root->add( new TextNode );
    root->add( new ElementNode );   
    // Etc.
}

干杯&amp;第h。,

PS:此示例代码中省略了错误检查,生命周期管理,迭代等。

答案 1 :(得分:5)

我会说void *几乎总是“坏”(对于某些坏的定义)。当然,可能有更好的方式来表达你正在尝试做的事情。如果是我编写这段代码并且我知道我要放入的值的类型,那么我会考虑使用Boost.Variant。如果我没有(例如,这是作为一个库提供给其他人“填满”),那么我会使用Boost.Any

例如:

template <class T, class U>
struct node
{
    typedef boost::variant<T, U> child_type;

    std::vector<child_type> children;

    void add_child(T const &t)
    {
        children.push_back(t);
    }

    void add_child(U const &u)
    {
        children.push_back(u);
    }
};

...

node<text, element> n;
n.add_child(text("foo"));

非增强型联合解决方案:

struct node
{
    struct child
    {
        int type; // 0 = text; 1 = element

        union 
        {
            text*    t;
            element* e;
        } u;
    };

    std::vector<child> children;

    void add_child(text* t)
    {
        child ch;
        ch.type = 0;
        ch.u.t  = t;

        children.push_back(ch);
    }

    void add_child(element* e)
    {
        child ch;
        ch.type = 1;
        ch.u.e  = t;

        children.push_back(ch);
    }
};

注意:对于使用类型联合的内存管理,你必须更加小心。

答案 2 :(得分:1)

如果你这样做,你怎么能让他们回来?从void*开始,无法确定地址上实际存储的内容。

编辑: 如果你总是对T*进行投射,那么你只需将T*作为参数。

答案 3 :(得分:1)

elementtext定义共享基类,然后add_child可以获取指向基类的指针,向量可以存储指向基类的指针。

答案 4 :(得分:1)

如果您的容器值仅限于少量类型,则可以使用boost::variant来实现此目的,如下所示:

#include <vector>
#include <boost/variant.hpp>

using namespace std;

class text
{ };

class element
{ };

template <typename T>
class node
{
    T cargo;

    static std::vector<boost::variant<text, element>> children;

    node(const T& cargo) : cargo(cargo)
    { };

    void add_child(const T& node)
    {
        children.push_back(boost::variant<text, element>(node));
    }
};

我冒昧地建议其他几个mod--使用const引用而不是node构造函数和add_child上的pass-by-value;使容器children保持静态,因为我认为每个node<T>都没有自己的容器是不合理的。在这种情况下,多线程使用add_child需要锁定。无论您是否可以在最终解决方案中使用Boost,这些注释都适用。

您可以使用vectorgetstatic_visitor元素执行操作 - 后者更可取,因为您可以使其成为通用元素 - 如图here所示。 vector迭代的一个示例,类似于您将用于此解决方案的内容:

class times_two_generic
    : public boost::static_visitor<>
{
public:

    template <typename T>
    void operator()( T & operand ) const
    {
        operand += operand;
        cout << operand << endl;
    }

};

std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );

times_two_generic visitor;
std::for_each(
      vec.begin(), vec.end()
   , boost::apply_visitor(visitor)
   );

输出是:

  

42

     

你好你好

答案 5 :(得分:0)

首先,使用void指针没有“坏”这样的事情。忘记所有的约定和bla-blas,并做最适合你的情况。

现在,在特定情况下,如果这两个类之间存在任何连接 - 您可以声明一个基类,以便这两个类继承它。然后,您可以声明该基类的指针向量。