C++ dll堆内存分配问题

Ans*_*Tan 5 c++ linux dll shared-libraries

从这个环节,我知道我们(应用程序)应始终从DLL删除堆内存分配,因为堆内存管理是不同的。

我有几个问题:

1.) .so 文件 (Linux) 怎么样,是一样的情况吗?

2.) 无论如何要确保应用程序和库(.dll 和 .so)使用相同的堆内存管理器或使用相同的堆内存部分?所以我们可以分别删除和新建(在 .dll/.so 中新建,在应用程序中删除)。

谢谢你。

Ted*_*gmo 4

1.) .so 文件(Linux)怎么样,是同样的情况吗?

是的,使用与最终链接的程序不同的标准 C++ 库实现构建的库可能会以稍微不同的方式进行分配。g++'slibstdc++clang++'slibc++是两种不同实现的示例。它们可能100% ABI 兼容 - 但第三个未知库可能不是。

2.)是否有办法确保应用程序和库(.dll 和 .so)使用相同的堆内存管理器或使用相同的堆内存部分?所以我们可以分别删除和新建(在.dll/.so处新建,在application处删除)。

不,编译到库中的内容就是库将使用的内容,除非有一种方法可以在加载库时对其进行初始化,告诉它使用特定的堆管理器。

请详细解释一下。我想知道 .so (Linux)是否只使用一个堆管理器来处理应用程序和 .so (库)。假设我的应用程序是由编译器版本A编译的,而我的.so是由编译器版本B编译的,还可以吗?

由于上述原因,不,你不能确定。由于您是库创建者,因此您可以创建 API,以便将库中类型的new内存delete分配/解除分配委托给编译到库中的成员函数,而该成员函数又执行真正的分配/解除分配(如operator new 中所述,运算符new[]运算符delete、运算符delete[])。new然后,可以在库和应用程序之间传递和传递指向您类型的对象的指针,并且可以delete在任一侧传递。


这是使用特定于类的分配函数的(不完整)示例:
void* T::operator new(std::size_t count);

以及特定于类的常用释放函数
void T::operator delete(void* ptr);

它包含foo.hppfoo.cpp用于使用该库创建libfoo.so(或libfoo.a)程序代码。

foo.hpp

#pragma once

#include <new>

class Foo {
public:
    // The "usual" part of your class definition:
    Foo(int x);
    ~Foo();

    // This part does NOT get compiled into your library.
    // It'll only be used by users of your library:
#ifndef BUILDING_LIB
    // Note: operator new and delete are static by default

    // single object allocation/deallocation:
    void* operator new(std::size_t /* byte_count */) { return Alloc(); }
    void operator delete(void* addr) { Free(addr); }

    // array allocation/deallocation:
    // TODO: operator new[] and delete[]
#endif
private:
    int value;

    // the functions really doing the memory management
    static void* Alloc();
    static void Free(void* p);
};
Run Code Online (Sandbox Code Playgroud)

foo.cpp

// Define BUILDING_LIB to disable the proxy operator new/delete functions when building
// the library.
#define BUILDING_LIB
#include "foo.hpp"

#include <cstdlib> // std::aligned_alloc
#include <iostream>

Foo::Foo(int x) : value(x) {
    std::cout << "Foo:Foo(" << value << ")\n";
}

Foo::~Foo() {
    std::cout << "Foo:~Foo() " << value << "\n";
}

void* Foo::Alloc() {
    void* addr = std::aligned_alloc(alignof(Foo), sizeof(Foo));
    std::cout << "Alloc() " << sizeof(Foo) << "\t@ " << addr << '\n';
    return addr;
}

void Foo::Free(void* addr) {
    std::cout << "Free()\t\t@ " << addr << '\n';
    std::free(addr);
}
Run Code Online (Sandbox Code Playgroud)

uselib.cpp

#include "foo.hpp"

#include <memory>

int main() {
    auto a = std::make_unique<Foo>(123); // heap allocation

    // An automatic variable will use the applications memory manager and will not
    // use Alloc/Free.
    Foo b(456);
}
Run Code Online (Sandbox Code Playgroud)

可能的输出:

Alloc() 4       @ 0x1af7eb0
Foo:Foo(123)
Foo:Foo(456)
Foo:~Foo() 456
Foo:~Foo() 123
Free()          @ 0x1af7eb0
Run Code Online (Sandbox Code Playgroud)