c++ - 获取没有对象的类的vtable

标签 c++ c++11 g++ undefined-behavior vptr

我正在尝试实现类似于 the first described here 的系统.也就是说,(ab)使用 vtable 修改来在运行时更改对象行为。这是我在我正在处理的 C++ 项目中创建高效类型通用包装器的尝试的一部分。

如果您无法访问该示例,则使用 memcpy()this 指针复制 vtable:

void setType( const DataType& newType )
{
    memcpy( this, &newType, sizeof(DataType) );
}

但是,我对这种方法有一个问题:我没有目标类的对象来从中复制 vtable,并且不想创建一个,因为某些类型的构造成本很高。

有没有办法在没有该类对象的情况下访问将被放置到给定类的对象中的 vtable?

如果它具有一定的可移植性会更好,但我基本上已经接受了它是特定于编译器的;因此,如果没有其他选择,GCC/G++ only 方法是可以接受的。我们还假设我只关心在相当标准的操作系统和架构上构建它。

我正在使用 C++11,这应该能以某种方式帮助我。

编辑:我想完全清楚,我知道这种行为有多危险。我更感兴趣的是这个想法,也许它在非常受控的情况下的狭窄应用,而不是它是一个生产软件的好主意,尽管我的介绍可能暗示了什么。

最佳答案

struct many_vtable {
  void(*dtor)(void*);
  void(*print)(void const*,std::ostream&);
};
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag = {};

template<class T>
many_vtable const* make_many_vtable(tag_t<T>){
  static const many_vtable retval = {
    // dtor
    [](void* p){
      reinterpret_cast<T*>(p)->~T();
    },
    // print
    [](void const*p, std::ostream& os){
      os<<*reinterpret_cast<T const*>(p);
    }
  };
  return &retval;
}
struct many {
  many_vtable const* vtable=nullptr;
  std::aligned_storage_t<100, alignof(double)> buff;
  void clear(){if(vtable) vtable->dtor(&buff);vtable=nullptr;}
  ~many(){ clear(); }
  many()=default;
  many(many const&)=delete; // not yet supported
  many& operator=(many const&)=delete; // not yet supported

  explicit operator bool()const{return vtable!=nullptr;}

  template<class T,class...Args>
  void emplace(Args&&...args){
    static_assert(alignof(T) <= alignof(double), "not enough alignment");
    static_assert(sizeof(T) <= 100, "not enough size");
    clear();
    ::new((void*)&buff) T(std::forward<Args>(args)...);
    vtable=make_many_vtable(tag<T>);
  }
  friend std::ostream& operator<<(std::ostream& os, many const&m){
    if(!m.vtable) return os;
    m.vtable->print(&m.buff, os);
    return os;
  }
};

这是一个手动虚表设计。它可以存储最多 100 个字节的任何内容,其对齐方式小于可以打印到流的 double 。

“删除”到更多(或不同)操作很容易。例如,能够复制/移动到另一个。

它不违反标准,并且与链接示例有类似的开销。

many m;
m.emplace<int>(3);
std::cout << m << '\n';
m.emplace<double>(3.14);
std::cout << m << '\n';

live example .

这是手动 vtable,因为我们基本上是手动重新实现 vtable 概念。

关于c++ - 获取没有对象的类的vtable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35801569/

相关文章:

c++ - 我无法在不违反 C++ 扩展规则的情况下创建匹配的构造函数

linux - 如何从生成的二进制文件中查看哪些静态库用于 gcc/g++ 编译?

c++ - vector 重新分配导致 malloc 错误

c++ - 无法在二维矩阵( vector 的 vector )中设置值

c++ - 选择可变参数模板最后一个参数的有效方法

c++ - std::map<,>.emplace() 产生错误

c++ - 如何使用 gcc 编译 SIMD 代码

c++ - 交错 std::map 插入和迭代

c++ - 二叉搜索树中的插入错误

c++ - gtest - 参数化测试限制,编译错误