【问题标题】:Can't access object's function after calling `operator new` explicitly显式调用`operator new`后无法访问对象的函数
【发布时间】:2018-01-12 20:16:55
【问题描述】:

我正在做一个项目,我必须实现 new operatordelete operator,并通过我自己的 MemoryManager 管理我的内存 - 它有可用内存列表。

为了分配我的列表和节点(不需要管理),我应该在调用malloc 之后显式调用operator new
当我试图调用一个函数 - setNext() 时,它会抛出一个异常:异常:EXC_BAD_ACCESS (code=1, address=0x0)

创建链表的哈希表:

MyHashTable::MyHashTable(size_t memorySize, void* startingPtr)
        :size(getLowerLog(memorySize) + 1), lists((LinkedList**)malloc(sizeof(LinkedList*) * size)), startingPtr(startingPtr) {
    for (size_t i = 0; i < size; i++) {
        auto memSize = (size_t) pow(2, i);
        void * l = malloc(sizeof(LinkedList));
        lists[i] = new (l) LinkedList(memSize);
        // Placement new
    }
    dividingMemory(memorySize, startingPtr);
}

dividingMemory 函数可以:

void MyHashTable::dividingMemory(size_t memorySize, void* startingPtr) {
    while (memorySize > 0) {
        size_t memPow = getLowerLog(memorySize);
        auto max = (size_t) pow(2, memPow);
        lists[max]->add(ptr);              // here is the call to LinkedList::add()
        startingPtr = ((char*) startingPtr) + max;
        memorySize -= max;
    }
}

LinkedList::add() :

void LinkedList::add(void * ptr) {
    void* p = malloc(sizeof(Node));
    Node * newNode = new (p) Node(ptr);
    // Placement new
    newNode->setNext(head);
    std::cout << "haha" << std::endl;
    head = newNode;
    size++;
}

整个节点类: 节点.h:

#ifndef EX3_NODE_H
#define EX3_NODE_H
#include <iostream>
#include <string>
class Node {
private:
    void* ptr;
    Node* next;
public:
    explicit Node(void*);
    inline Node* getNext() const {
        return next;
    }
    inline void setNext(Node* next) {
        this->next = next;
    }
    ~Node() = default;
};
#endif //EX3_NODE_H

Node.cpp:

Node::Node(void * ptr):ptr(ptr) { }

我尝试调用另一个函数 (toString),但它退出了。

我做错了什么?

我尝试了@Ben Voigt 的答案,但没有解决。

【问题讨论】:

  • new 的使用通常称为“新位置”。
  • @FrançoisAndrieux 是的,我知道..这就是为什么它出现在 malloc 之后..
  • 这不是一个最小的、完整的和可验证的例子。
  • 还有一个问题:MyHashTable::dividingMemory() 中的行:lists[key]-&gt;add(ptr);keyptr 来自哪里?

标签: c++ placement-new


【解决方案1】:

您正在丢弃位置new 的返回值,这是获取指向新构造对象的指针的唯一形式上正确的方法。然后,您在传递给placement new 的原始存储指针上调用成员函数。不要那样做。

这是将 malloc 与placement new 一起使用的正确方法:

void* rawBlock = malloc(sizeof(Node));
Node* newNode = new (rawBlock) Node(ptr);

// later
newNode->~Node();
free(rawBlock);

【讨论】:

  • 假设Node* foo = (some pointer)Node* bar = new (foo) Node(ptr),在什么情况下foobar不是别名?或者您必须只使用bar 来满足一些法律术语,即在将foo 用作新展示位置的参数后您不能使用它?
  • +1 整个线程中的每个人。它很有教育意义,我很高兴我不需要在这个详细和精细的控制级别上涉足 C++ 内存管理和对象构造/销毁。
  • @BenVoigt 很高兴知道为什么存在错误,而不仅仅是在哪里 是错误。
  • @zneak:对于数组,它们绝对不能保证相等。对于单个对象,两个指针在内存中的地址相同,但编译器严格别名分析对它们的处理仍然不同(请参阅严格别名规则)。同样是的,在用全新的对象覆盖指针所指向的内容后,您可以使用指针做什么是有限制的。
  • @StavAlfi:我确实解释过,代码混淆了指向原始存储的指针和指向对象的指针。
【解决方案2】:

逻辑错误,我试图访问一个未定义的内存位置。

auto max = (size_t) pow(2, memPow);
lists[max]->add(ptr);

应该是:

auto max = (size_t) pow(2, memPow);
lists[(log(max) / log(2)]->add(ptr);

【讨论】:

  • 你为什么要这样计算? log(max) / log(2) 就是 memPow
猜你喜欢
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 1970-01-01
相关资源
最近更新 更多