gpt4 book ai didi

c++ - CMake 生成的 DLL 和 Curiously Recurring 模板 (C++) 的不正确行为

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:11:57 24 4
gpt4 key购买 nike

我在 Windows 上遇到了 CMake 生成的 DLL 文件的令人困惑的问题。在我的库中,我使用 Curiously Recurring Template Pattern 为某些类提供唯一的 ID 号:

// da/Attribute.h:

#ifndef DA_ATTRIBUTE_H
#define DA_ATTRIBUTE_H

namespace da {

typedef unsigned int AttributeId;

class AttributeBase {
public:
virtual AttributeId getTypeId() const=0;

protected:
/** Static ID counter. Every class that derives da::AttributeBase is
assigned an increment of this counter as its type ID number */
static AttributeId sNextId;

};

template <class Derived>
class Attribute : public AttributeBase {
private:
static AttributeId msTypeId;

public:
Attribute() {
if (msTypeId == 0) {
msTypeId = ++sNextId;
}
}

virtual ~Attribute() {

}

/** For static contexts */
static AttributeId typeId() {
if (msTypeId == 0) {
msTypeId = ++sNextId;
}

return msTypeId;
}

AttributeId getTypeId() const {
return typeId();
}

};

template <class Derived> AttributeId Attribute<Derived>::msTypeId = 0;

}

#endif

问题是,当我将 DLL 链接到可执行项目时,不同的 ID 方法似乎有些不一致。例如:

// Foo.h
struct Foo : public da::Attribute<Foo> {
Foo() { }
};

...

// main.cpp
Foo *foo = new Foo;

Foo->getTypeId() == 1 // True
Foo::typeId() == 1 // Should be true, but isn't. Foo::typeId() == 2

运行 GDB,在 Foo::getTypeID() 中中断,我发现“msTypeId”和“Foo::msTypeId”具有不同的内存地址。到底是怎么回事。 p>

不过,只有在 DLL 中定义了 Foo 时才会发生这种情况。 (显然只有在 Windows 7 中——我的 Debian 构建中没有这个问题)如果我在 main.cpp 中创建派生类,或者如果我只是将库中的所有代码编译到可执行文件中,则跳过完全是 DLL 步骤,它没有问题。

一切都是使用 MSYS 和 MinGW 编译的,在 Windows 7 家庭高级版上使用 GCC 4.7。

这是库的 CMakeLists.txt,以防我在上面搞砸了:

cmake_minimum_required(VERSION 2.6)
project(foo)

add_definitions(-std=c++0x)
set(CMAKE_BUILD_TYPE Debug)

set(sources
Foo.cpp
)

add_library(foo SHARED ${sources})

最佳答案

您必须从共享库中导出类型。这是使用 __declspec(dllexport) and __declspec(dllimport) 完成的装饰器。阅读 MSDN 文档;它相当复杂。

由于头文件在构建库时需要有__declspec(dllexport),在编译使用它的代码时需要有__declspec(dllimport),所以通常定义一个符号,通常称为 LIBRARYNAME_EXPORT 并根据是否定义了 LIBRARYNAME_EXPORTS #ifdefs。

CMake 在构建(共享)库时自动定义 target_EXPORTS。可以通过设置 DEFINE_SYMBOL 目标属性来覆盖它。

Unix 选择不同的路径,默认情况下导出和导入共享库中的所有符号(静态和显式隐藏的符号除外)。这会导致一些性能损失,因为需要解析更多符号,但它更易于使用(无需更改即可从静态库切换到共享库)并且更加灵活(即您可以覆盖共享库中的符号,这你不能在 Windows 中做)。

关于c++ - CMake 生成的 DLL 和 Curiously Recurring 模板 (C++) 的不正确行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13009497/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com