模板的编译查询 [英] Compilation Query for templates

查看:65
本文介绍了模板的编译查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有2个CPP文件



MyFile1.cpp

MyFile2.cpp



MyFile1.cpp已经



Lets say I have 2 CPP files

MyFile1.cpp
MyFile2.cpp

MyFile1.cpp has

#include <vector>

std::vector<int> obj1;





和MyFile2具有相同的代码:





and MyFile2 has the same code :

#include <vector>

std::vector<int> obj2;





现在我分别编译这两个文件并得到两个obj文件。 MyFile1.obj和MyFile2.obj



现在为什么不将这两个文件链接到make和executable时会出现链接错误。



这假设每个文件都有



Now I compile these two files separately and get two obj files. MyFile1.obj and MyFile2.obj

Now why don't I get linking error when linking these two files to make and executable.

This is assuming the each file will have an instantiation of

vector<int>

类的实例化。



在这种情况下,在链接过程中后台会发生什么。

class.

What happens in the background during the linking process in this case.

推荐答案

如果您想知道链接器如何工作,看看这些链接:

连卡人初学者指南 [ ^ ]

编译,链接过程如何工作? [ ^ ]



如果你想知道为什么你以前有链接器错误,现在你没有。



在上一次问题的迭代中你在两个文件中都有一个具有相同名称的全局变量:

In case you wish to know how a linker works, check out these links:
Beginner's Guide to Linkers[^]
How does the compilation, linking process work?[^]

In case you wish to know why you previously got a linker error, and now you don't.

In the previous iteration of your question you had a global variable with the same name in both files:
std::vector<int> obj;





导致链接器错误。解决方案是重命名它(但可能不是你想要的),或者将外部关键字添加到其中一个中,如下所示:



That results in a linker error. The solution would be to either rename it (but probably not what you want), or to add the external keyword to one of them, like so:

external std::vector<int> obj;





这不会重新定义变量,但允许你在另一个文件中使用它。



所以,显然,重命名全局变量(正如你在问题的第4节中所做的那样)不会导致链接器错误。



This will not redefine the variable, but will allow you to use it in the other file.

So, obviously, renaming the global variables (as you did in v4 of your question) will not result in a linker error.


你的问题是关联的如何实例化模板类。没有冲突,因为在编译器创建obj1和obj2之前,类不存在。





http://msdn.microsoft.com/en-us/library/7y5ca42y.aspx [ ^ ]





http://www.learncpp。 com / cpp-tutorial / 142-function-template-instances / [ ^ ]



std :: vector不是类定义,而是一组用于创建类的规则。
Your question relates to how templated classes are instantiated. There is no conflict because before obj1 and obj2 are created by the compiler the class as such does not exist.


http://msdn.microsoft.com/en-us/library/7y5ca42y.aspx[^]


http://www.learncpp.com/cpp-tutorial/142-function-template-instances/[^]

std::vector is not a class definition but a set of rules for creating a class.


也许您的问题与模板的方法有关,而与实际的模板实例(如obj1和obj2)无关。模板的所有使用方法都被编译到使用它们的所有编译单元的目标文件中。这不是与模板相关的问题,它是一个更常见的问题,与驻留在两个或多个编译单元可见的公共标题中的内联函数和方法有关。

标题中的内联函数/方法示例:

Maybe your question is related to the methods of the template and not the actual template instances (like obj1 and obj2). All used methods of the template get compiled into the object file of all compilation units that use them. This is not a template related "problem", it is a more general problem related to inline functions and methods residing in public headers visible by two or more compilation units.
Example inline functions/methods in a header:
inline void MyGlobalFunc()
{
}

class MyClass
{
public:
    // This constructor is automatically inline because the body of this function
    // was defined inside the class declaration!
    MyClass()
    {
    }

    // Automatically inline for the same reason as the constructor.
    void Method1()
    {
    }

    // Automatically inline for the same reason as the constructor.
    // This declaration would be the same without the optional inline keyword.
    inline void Method2()
    {
    }

    // See the method definition below.
    void Method3();
    // See the method definition below.
    void Method4();
};

// Not inline!!! Because the method body was specified outside the class body
// without the inline keyword!!! This should be put into a .cpp file!
void MyClass::Method3()
{

}

// Inline because you specified the inline keyword like in case of the global function.
inline void MyClass::Method4()
{

}



允许在许多目标文件中存在相同的内联函数/方法,链接器只保留其中一个。只有一个大问题!!!链接器仅通过其签名来比较内联方法!如果您成功将两个内联方法或函数放入具有相同签名但具有不同实现的两个不同目标文件中,那么您的东西将链接,但链接器中将只保留其中一个实现(随机),因此您的一个目标文件将调用在另一个中找到的实现导致错误的行为,有时很难找到错误/崩溃!它很容易将内联函数/方法与不同的实现放入两个目标文件中,这通常不使用标题!让我演示一下:

x1.cpp:


The same inline function/method is allowed to be present in many object files and the linker will keep only one of these. There is only one big problem!!! The linker compares the inline methods only by their signature! If you succeed to put two inline methods or functions into two different object files with the same signature but with different implementation then your stuff will link but only one of the implementations will be kept by the linker (randomly) so one of your object file will call the implementation found in the other one resulting in wrong behavior and sometimes very hard to find bugs/crashes!!! Its easy to put inline functions/methods with different implementation into two object files, this usually happens without using headers! Let me demonstrate that:
x1.cpp:

#include <stdio.h>

struct SInlineTest
{
	SInlineTest()
	{
		printf("%s 1\n", __FUNCTION__);
	}
	~SInlineTest()
	{
		printf("%s 1\n", __FUNCTION__);
	}
};


inline void InlineFunc()
{
	printf("%s 1\n", __FUNCTION__);
}

void InlineTest()
{
	SInlineTest t;
	InlineFunc();
}





x2.cpp:



x2.cpp:

#include <stdio.h>

struct SInlineTest
{
    SInlineTest()
    {
        printf("%s 2\n", __FUNCTION__);
    }
    ~SInlineTest()
    {
        printf("%s 2\n", __FUNCTION__);
    }
};

inline void InlineFunc()
{
    printf("%s 2\n", __FUNCTION__);
}

void InlineTest2()
{
    SInlineTest t;
    InlineFunc();
}

int main()
{
    void InlineTest();
    InlineTest();
    printf("-----------------\n");
    InlineTest2();
    return 0;
}





这里链接器只保留一个InlineFunc()版本,构造函数和破坏者。链接器将随机抛出其中一个版本。如果在.cpp文件中找到类/结构声明,建议将这些类声明放入匿名命名空间以避免链接器冲突,如果内联全局函数删除inline关键字并将函数放入匿名命名空间或者使用static关键字或两者都是有效的。



编辑:如果项目规模较大,我的生活中只遇到过两次这个bug。当两个人在两个具有相同名称的不同.cpp文件中使用一些小的简单结构时,通常会发生此错误(如SItem - 这是一个流行的名称以及其他一些)并且通常这些结构的内联ctor或dtor冲突导致一个链接但行为不端的二进制文件。



Here the linker will keep only one of the InlineFunc() versions and the same is true for the constructors and the destructors. The linker will randomly throw out one of the versions. In case of class/struct declarations found inside .cpp files its advisable to put these class declarations into an anonymous namespace to avoid the linker conflict, in case of inline global function remove the "inline" keyword and either put the function into an anonymous namespace or use the static keyword or both is also valid.

I've encountered this bug only twice in my life in case of bigger projects. This bug usually happens when two people use some small simple structs in two different .cpp files with the same name (like SItem - this is a popular name along with some other ones) and usually the inline ctor or dtor of these structs conflict resulting in a linking but misbehaving binary.


这篇关于模板的编译查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆