【发布时间】:2013-03-07 23:25:51
【问题描述】:
我正在阅读“现代 C++ 设计”并想到了构建一个类的想法,该类的作用类似于指针,但它会在堆栈上而不是在堆上分配对象。它可以用于通常会返回指向在堆上分配的对象的指针的函数。
我会在粘贴代码之前问我的问题:
- 已经有类似的东西了吗?
- 有机会使用吗? (当然,如果实施得更准确)
- 为什么使用
boost::mpl::max_element(已注释掉)的版本不起作用? - 如果没有参数,如何调用模板化构造函数? (我的意思是:
template <class U> StackPointer() { ... })?
代码如下:
#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/max_element.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/front.hpp>
template <class V, size_t VS=boost::mpl::size<V>::type::value>
struct max_size
{
typedef typename boost::mpl::pop_front<V>::type subvector;
typedef typename boost::mpl::front<V>::type front_type;
static size_t const value = sizeof(front_type) > max_size<subvector>::value ?
sizeof(front_type) : max_size<subvector>::value;
};
template <class V>
struct max_size<V, 0>
{
static size_t const value = 0;
};
class StackPointerImplBase
{
public:
virtual void clone(char const* from, char* to) const = 0;
};
template <class T>
class StackPointerImpl : public StackPointerImplBase
{
public:
virtual void clone(char const* from, char *to) const
{
new(to) T(*reinterpret_cast<T const*>(from));
}
};
template <class Base, class DerivedTypes>
class StackPointer
{
public:
template <class T>
StackPointer(T const& t)
{
std::cout << "Size of m_buf: " << sizeof(m_buf) << std::endl;
new(m_impl_buf) StackPointerImpl<T>();
new(m_buf) T(t);
}
StackPointer(StackPointer const& sp)
{
//TODO: COPY m_impl_buf
reinterpret_cast<StackPointerImplBase const*>(sp.m_impl_buf)->clone(sp.m_buf, m_buf);
}
public:
~StackPointer()
{
get_pointer()->~Base();
}
Base* operator->()
{
return get_pointer();
}
private:
Base* get_pointer()
{
return reinterpret_cast<Base*>(m_buf);
}
private:
//typedef max_size<DerivedTypes> xxx_type;
//typedef typename boost::mpl::max_element<DerivedTypes>::type::type biggest_type;
//char m_buf[sizeof(typename boost::mpl::max_element<DerivedTypes>::type::type)];
char m_buf[max_size<DerivedTypes>::value];
char m_impl_buf[sizeof(StackPointerImplBase)];
};
class Shape
{
public:
virtual ~Shape() {}
virtual void say() const { std::cout << "I'm a shape" << std::endl; }
};
class Circle : public Shape
{
public:
virtual void say() const { std::cout << "I'm a circle" << std::endl; }
private:
float m_x;
float m_y;
float m_r;
};
class Line : public Shape
{
public:
virtual void say() const { std::cout << "I'm a Line" << std::endl; }
private:
float m_x1;
float m_y1;
float m_x2;
float m_y2;
};
typedef StackPointer<Shape, boost::mpl::vector<Circle, Line> > ShapeStackPtr;
ShapeStackPtr read_shape()
{
Line c;
return ShapeStackPtr(c);
}
int main(int argc, char *argv[])
{
{
ShapeStackPtr shape = read_shape();
shape->say();
}
return 0;
}
【问题讨论】:
-
为什么不想使用堆?
-
在我看来,您的方法的一个主要问题是必须事先知道所有派生类。如果我想向
Shape添加一个新的子类怎么办?我需要更改ShapeStackPtr的所有用途,或者创建一个新类型的StackPointer。如果可以使指针仅与基类一起使用,这可能会很有趣,但我怀疑这是可能的。另一方面,我认为分配性能问题可能最好通过使用自定义分配器或覆盖 new/delete 来处理。
标签: c++ templates metaprogramming template-meta-programming boost-mpl