【问题标题】:Initializing a class using malloc使用 malloc 初始化一个类
【发布时间】:2011-04-10 18:55:45
【问题描述】:

我正在使用 C++ 作为中间语言为 avr 开发一种玩具语言,问题是 avr-gcc 没有新的实现。我的所有对象都派生自具有虚拟方法的类 Object,当我使用以下指令创建带有 malloc 的浮点对象时,

Can I implement the Factory Method pattern in C++ without using new?

一旦我将它转换为 Object 以传递并返回到 Float,我的程序就会崩溃,答案中的 cmets 说这是由于 vtable 未正确初始化,所以我如何在不使用 new 的情况下创建 c++ 对象并正确设置了 vtable?

【问题讨论】:

  • 我想知道这种结构的用途是什么?
  • @rubenvb,他正在研究一种语言创意,那么这显然不是您问题的答案吗?

标签: c++ c gcc embedded g++


【解决方案1】:

似乎支持 new 作为一种语言结构,但未实现作为其基础并进行实际分配的 operator new 代码。

通过在源代码中为operator new 提供自己的实现应该很容易解决这个问题:

在需要new的任何文件中包含的某些头文件中

#include <stdlib.h> 

void * operator new(size_t size); 
void operator delete(void * ptr);

在单个 cpp 文件中。

void * operator new(size_t size) 
{ 
  return malloc(size); 
} 

void operator delete(void * ptr) 
{ 
  free(ptr); 
} 

来源:avrfreaks.net 上的this post,其中还包含有关您可能想要/需要自己实现的其他一些东西的信息。

【讨论】:

  • @ken,这就是我从上面尝试过的线程,但它在 os x 上的 gcc 中崩溃了。我在路上,手边没有arduino。
  • vtable、rtti 等 ABI 内容与指针的偏移量为负。因此,分配 24 个额外字节并返回一个指向 malloc 返回指针之外 24 个字节的指针。
  • @Heath:真的吗?听起来它不适用于数组或堆栈分配。
  • 其实operator new的实现不应该这么简单。要获得完全符合new 标准的实现,您需要检查来自mallocthrow std::bad_alloc 的返回是否为空。
  • @Ken,我 malloc d 类的大小而没有覆盖 new/delete 以快速测试,崩溃了,然后回家尝试了你的 sn-p 并且它起作用了。
【解决方案2】:

这取决于您要编译到的硬件平台,但布局通常在不同的实现中非常相似。毕竟最早的C++是CFRONT,它把C++编译成C...

平台相关问题和内存布局将在“平台 C++ ABI”中描述,其中 ABI 代表“应用程序二进制接口”。

struct Cxx_ABI_Header
{
    unsigned inheritance_backward_offset;  /* Must be Zero for base object */
    unsigned rtti; /* Each class has its own signature. */
    void * vtable; /* Pointer to array of virtual function pointers. */
}

struct object_one
{
     char * file_name;
     int file_descriptor;
}

int object_one_create_file(struct object_one *);
int object_one_delete_file(struct object_one *);
int object_one_update_file(struct object_one *, off_t offset, 
                           size_t nbytes_replace, size_t nbytes_supplied,
                           char * buf);
int object_one_read_file(struct object_one *, off_t offset, 
                         size_t nbytes_read, char * buf);
int object_one_op_noauthz(struct object_one *)
{
    return ENOACCESS;
}

void * CRUD_vtable_authenticated_user = {
    { object_one_create_file, object_one_read_file,
      object_one_update_file, object_one_delete_file }};

void * CRUD_vtable_guest = {
    { object_one_op_noauthz, object_one_read_file,
      object_one_op_noauthz, object_one_op_noauthz }};

这是一个可能的构造函数,它实际上产生了两种不同的“object_one”。

struct object_one * new_object_one(char * filespec, int user_id)
{
    size_t n_bytes = sizeof(struct Cxx_ABI_Header) + sizeof(struct object_one);
    void * pheap = malloc(n_bytes);
    struct * pCxx_ABI_Header pcxx = pheap;
    struct * pObject  pobj = (void *)((char *)pheap 
                                               + sizeof(struct Cxx_ABI_Header));

    if (!pheap) ...

    pcxx->inheritance_backward_offset = 0;
    pcxx->rtti = /* You tell me? */
    pcxx->vtable = (userid < 0 ) ? CRUD_vtable_guest 
                                 : CRUD_vtable_authenticated_user;

    pobj->file_name = strdup(filespec);
    pobj->file_descriptor = 0;

    return pobj;
}

瞧——通过?:实现多态性

无论如何,享受语言实验,祝你在 C++ 上取得进步。通过将您的努力建立在 C 上,您将有一个良好的开端。 ;)

【讨论】:

    【解决方案3】:

    您可以使用 malloc 后跟placement-new ,它将正确创建对象,并在您指定的位置构造它。

    当然,这仍然意味着使用关键字“new”,但如果您真正想做的是处理内存/堆管理而不是完全禁止该关键字,那么它可能会实现您正在尝试的目标。

    【讨论】:

      【解决方案4】:

      如果您想针对特定编译器的一个特定版本定制实现,那么可以,对于 GCC,只需查看 GCC 代码中 new 的实现即可。

      否则没有。您可以做的是两因素初始化。首先分配内存(malloc()operator new()),然后使用placement new 进行初始化。

      【讨论】:

      • 他想要一个不使用 new 的解决方案,这意味着,我想,他也不想要放置 new。
      • @Nawaz 好吧,我在第一句话中就提到了。
      • @Nawaz:我不分享这个;有什么合理的理由使用placement new来实现目标?
      • @sehe : OP 说 问题是 avr-gcc 没有新的实现
      • C++ 无法在不使用new 或放置new 的情况下调用非堆栈分配对象的构造函数。放置new 可能与普通new 一样被破坏,修复应该相当简单。
      猜你喜欢
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-08
      • 2014-11-18
      • 1970-01-01
      相关资源
      最近更新 更多