VS 2008 令人恼火的复制构造函数链接依赖
我在 Visual Studio 2008 C++ 编译器中遇到了以下恼人且看似不正确的行为:
假设我有一个类库 - Car.lib - 它使用“Car”类,其标头名为“Car.h”:
class Car
{
public:
void Drive()
{
Accelerate();
}
void Accelerate();
};
什么我实际上想做的是使用 Car 标头(对于某些其他功能),但不必与 Car.lib 本身链接(实际的类不称为“Car”,但我正在清理这个示例)。
如果我在用于构建托管 C++ .dll 的 .cpp 文件中#include“Car.h”,但从不引用 Car,则一切都会正常编译和链接。这是因为我从未实例化过 Car 对象。
但是,以下内容:
namespace {
class Car
{
public:
Car(const Car& rhs)
{
Accelerate();
}
void Accelerate();
};
}
给我留下了链接错误:
Error 2 error LNK2001: unresolved external symbol "public: void __thiscall `anonymous namespace'::Car::Accelerate(void)" (?Accelerate@Car@?A0xce3bb5ed@@$$FQAEXXZ) CREObjectWrapper.obj CREObjectBuilderWrapper
注意,我已在匿名命名空间内声明了整个内容,因此在任何情况下都无法从 .DLL 导出 Car 函数。
我可以明确保证 Car 不会在其他任何地方被引用,因为我刚刚创建了这个类并从 scatch 中输入了定义。 “真正的”类是一个不同的名称。
将复制构造函数声明为外线并没有什么区别。即以下内容也无法链接:
class Car
{
public:
Car(const Car& rhs);
void Accelerate();
};
Car::Car(const Car& rhs)
{
Accelerate();
}
这是专门与复制构造函数注释有关的内容,因为例如以下内容,确实链接:
class Car
{
public:
Car()
{
Accelerate();
}
void Accelerate();
};
我不是 C++ 标准大师,但这似乎不正确大部头书。当然,编译器仍然不必生成任何调用 Car 复制构造函数的代码。
任何人都可以确认这种行为是否正确?我已经有一段时间没有使用 C++ 了 - 但我不认为这曾经是 Visual Studio 6.0 的问题。
这可能是因为我正在构建托管 C++ .dll。(后来:是的,这正是问题所在。 /clr 选项似乎引入了这种依赖性)。
这是用于构建项目的命令行:
/OUT:"..\..\bin\Release\CREObjectBuilderWrapper.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\qa\lib" /LIBPATH:"..\..\lib\release" /LIBPATH:"..\..\lib\VDB" /DLL /MANIFEST /MANIFESTFILE:"Release\ObjectBuilderWrapper.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"c:\Release\ObjectBuilderWrapper.pdb" /LTCG /DYNAMICBASE:NO /FIXED:No /MACHINE:X86 /KEYFILE:"c:\src\ObjectBuilderWrapper\\FI.snk" /ERRORREPORT:PROMPT CRERuntime.lib QA.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
任何人都可以建议一种解决方法,允许人们从复制构造函数中“重用” Accelerate 方法,并且仍然将复制构造函数声明为内联吗?
I've run into the following annoying and seemingly incorrect behaviour in the Visual Studio 2008 C++ compiler:
Suppose I have a class library - Car.lib - that uses a "Car" class, with a header called "Car.h":
class Car
{
public:
void Drive()
{
Accelerate();
}
void Accelerate();
};
What I'm actually trying to do is use the Car headers (for some other functions), but without having to link with Car.lib itself (the actual class is not called "Car" but I am sanitising this example).
If I #include "Car.h" in the .cpp file used to build a managed C++ .dll, but never refer to Car, everything compiles and links fine. This is because I never instantiate a Car object.
However, the following:
namespace {
class Car
{
public:
Car(const Car& rhs)
{
Accelerate();
}
void Accelerate();
};
}
leaves me with the link error:
Error 2 error LNK2001: unresolved external symbol "public: void __thiscall `anonymous namespace'::Car::Accelerate(void)" (?Accelerate@Car@?A0xce3bb5ed@@$FQAEXXZ) CREObjectWrapper.obj CREObjectBuilderWrapper
Note I've declared the whole thing inside an anonymous namespace so there's no way that the Car functions could be exported from the .DLL in any case.
I can categorically guarantee that Car is not referenced anywhere else, because I just made this class up and typed in the definition from scatch. The "real" class is a different name.
Declaring the copy constructor out-of-line makes no difference. i.e. the following also fails to link:
class Car
{
public:
Car(const Car& rhs);
void Accelerate();
};
Car::Car(const Car& rhs)
{
Accelerate();
}
It's something specifically to do with the copy constructor note, because the following, for example, does link:
class Car
{
public:
Car()
{
Accelerate();
}
void Accelerate();
};
I am not a C++ standards guru but this doesn't seem correct to me. Surely the compiler still should not have had to even generate any code that calls the Car copy constructor.
Can anyone confirm if this behaviour is correct? It's been a while since I used C++ - but I don't think this used to be an issue with Visual Studio 6.0 for example.
It might be because I am building a managed C++ .dll. (Later: yes, this is exactly the issue. The /clr option appears to introduce this dependency).
Here is the command line being used to build the project:
/OUT:"..\..\bin\Release\CREObjectBuilderWrapper.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\qa\lib" /LIBPATH:"..\..\lib\release" /LIBPATH:"..\..\lib\VDB" /DLL /MANIFEST /MANIFESTFILE:"Release\ObjectBuilderWrapper.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"c:\Release\ObjectBuilderWrapper.pdb" /LTCG /DYNAMICBASE:NO /FIXED:No /MACHINE:X86 /KEYFILE:"c:\src\ObjectBuilderWrapper\\FI.snk" /ERRORREPORT:PROMPT CRERuntime.lib QA.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
Can anyone suggest a workaround that allows one to "re-use" the Accelerate method from within the copy constructor and still have the copy constructor declared inline?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我尝试在本机项目中使用 VS2008 编译您的示例;完全没问题。但我后来在一个托管项目中尝试过,但遇到了同样的错误。所以这显然与托管代码有关。
由于 C++/CLI 是标准之外的扩展,因此我们不应该奇怪它会做一些意想不到的事情。不幸的是,我无法指出托管环境需要运行复制构造函数的原因。
I have tried to compile your example with VS2008 in a native project; no problem at all. But I have then tried in a managed project and I get the same error. So this is clearly something to do with managed code.
Since C++/CLI is an extension outside the standard, we should not wonder that it does some unexpected things. Not that I can point out the reason why the managed environment needs to run the copy constructor, unfortunately.
嗯,看起来有些东西需要复制构造函数,但不需要默认构造函数。一个例子是:
无论您是否实际填充它。
Well, it looks like something needs a copy constructor but doesn't need a default constructor. An example of this would be:
whether or not you actually populate it.
刚刚在 VS2008 中使用匿名名称空间尝试了您的代码,它可以正常编译和链接。
确保您确实没有在任何地方引用
Car
。如果完全删除
Car
的定义会发生什么?一切仍然可以编译吗?Just tried your code with the anonymous namespace with VS2008 and it compiles and links fine.
Make sure you really actually don't refer to
Car
anywhere.What happens if you erase the definition of
Car
completely? does everything still compiles?