是否有充分的理由在h文件而不是cpp文件中使用包含防护?

问题描述 投票:-2回答:1

例如,从我对C ++和clang ++的基本了解,我不明白为什么以下设置不受欢迎:

似乎在标头中使用变体会产生更多输出,需要更特定的编译器设置,并且在函数声明中需要重复。

clang++ --std=c++2a Start.cpp -o Start.o; ./Start.o

Start.cpp

#include "A.cpp"
#include "B.cpp"

int main (
    int argc,
    char** argv
) {
    A();
    B();

    return 0;
}

A.cpp

#ifndef A_H
#define A_H

#include <stdio.h>
#include "C.cpp"

void A() {
    printf("A\n");
    C();
}

#endif

B.cpp

#ifndef B_H
#define B_H

#include <stdio.h>
#include "C.cpp"

void B() {
    printf("B\n");
    C();
}

#endif

C.cpp

#ifndef C_H
#define C_H

#include <stdio.h>

void C() {
    printf("C\n");
}

#endif
c++ clang++
1个回答
1
投票
如果将该目标文件与另一个包含一个cpp文件的目标文件链接,则该程序将违反一个定义规则,因为这些文件包含非内联函数的定义。

而且,通常会编译cpp文件并将它们链接在一起。如果您既编译这些cpp文件中的任何一个,同时又将其包含到另一个转换单元中,则将遇到违反ODR的情况。

为了解决此问题,如果您将一个文件包含在其他文件中,那么通常应确保所包含的文件(即头文件)不包含任何包含在多个翻译单元中的违反ODR的内容。

此外,遵循常用的命名方案也是一种最佳实践。对头文件使用cpp扩展名与所有常见的命名方案相反。

是否有充分的理由在h文件而不是cpp文件中使用包含防护?

无论您如何命名头文件,都应始终在所有头文件中使用include guard。 (尽管从技术上讲,在某些标头中不需要标头保护,但是简单地使用标头保护比跟踪是否需要它更容易)。


现在,如果您想知道是否可以将所有函数定义放在一个翻译单元中:是的,可以。这具有优点和缺点:

单个TU的优点:由于没有重复编译模板和其他内联函数,因此从头开始的编译时间更快。另外,由于没有翻译单元边界会妨碍优化,因此优化效果也更好-跨TU边界工作的链接时间优化削弱了这一优势。

缺点:对程序的任何更改只会导致重新编译修改的翻译单元。如果只有一个翻译单元是整个程序,那么任何更改,无论大小如何,都将需要重新编译整个程序。这是非常不希望的。链接时间优化可消除此缺点,链接时间优化可导致链接太慢,以至于从重用翻译单元节省的时间变得微不足道。

© www.soinside.com 2019 - 2024. All rights reserved.