默认情况下,pragma once 应该位于每个 header 之上
should pragma once be on top of every header as default
我正在学习 C++,我遇到(并修复)了一个看起来非常 classic 的问题:
g++ main.cpp A.cpp B.cpp -o out
In file included from B.h:1,
from main.cpp:3:
A.h:1:7: error: redefinition of ‘class A’
1 | class A {
| ^
In file included from main.cpp:2:
通过快速研究(假设我理解正确),发生这种情况是因为 #include operation is not "idempotent"(我在这个问题中发现的一个术语)。
为了说明我的问题,我提出了一个最小的工作示例。
main.cpp
#include "A.h"
#include "B.h"
#include <iostream>
int main () {
std::cout << "Hello world" << std::endl;
A a;
B b(a);
return 0;
}
A.h
#include <iostream>
class A {
public:
void test();
};
A.cpp
#include "A.h"
void A::test () {
std::cout << "test" << std::endl;
}
B.h
#include "A.h"
class B {
public:
B(A);
};
B.cpp
#include "B.h"
#include <iostream>
B::B(A a){
a.test();
}
使用 g++ main.cpp A.cpp B.cpp
或更具体地说 g++ -c main.cpp
编译程序将失败并出现上述错误。
我了解到编译器 transcludes 在编译 main.cpp 时“A”的 header 两次(一次在 main.cpp:1 和一次在 B.h:1 在其自身包含在 main.cpp:2) 期间。实际上,编译器 'sees' 定义了 class A
两次,并认为我们定义了 A 两次。
我不明白的是包含守卫:
要解决此问题,可以在多次包含的文件顶部使用关键字:pragma once
:
A.h fixed with #pragma once
#pragma once
#include <iostream>
class A {
public:
void test();
};
允许程序顺利编译。
对我来说,这表明我应该在每个 header 开始时使用 #pragma once !!! 哪个不对?这是常见的做法吗?如果是这样,有没有办法在编译时执行此操作(例如作为标志)?
如果我不这样做,我可能不会使用 object A 作为 class A 的成员,也不会将其作为参数传递给 B(如在我的示例中的 B 的构造函数中),如果这样的话A 和 B 可以在另一个文件中单独使用;除非每次出现问题时我都反应性地添加 #pragma once
,这对我来说似乎是“肮脏的”。此外,我无法与任何人分享我的资源,因为担心他们会遇到我的两个 object 的情况,而不必自己在我的文件中添加 pragma once
。
我错过了什么?有没有办法完全避免这个问题?
您可以使用 #pragma once or the more "traditional" include guard.
如您所料,它应该存在于每个头文件中。
在此示例中,您提供了:
#pragma once
#include <iostream>
class A {
public:
void test();
};
不保证适用于所有环境。 (就像其他评论提到的那样。)以及 Circular Dependices.
但是使用两个预处理器指令:#ifndef
和 #endif
(包括守卫)
防止头文件被意外包含多次。
#ifndef A_H
告诉预处理器查找名为 A_H
的常量,该常量尚未使用 #define
指令创建。
现在,如果 A_H
常量尚未定义,则程序中将包含以下行:
class A {
public:
void test();
};
例如使用 ifndef
和 #endif
:
#ifndef A_H
#define A_H
class A {
public:
void test();
};
#endif
To me this suggest that I should start every header with #pragma once !!! Wich can't be right is it?
可能是对的。虽然理论上可能有点夸张。
Is it common practice?
是的,是的。如果我们 包括 使用宏 header 守卫的另一个选项到相同的实践中,这是相当普遍的。
If so, Is there a way to do that at compile time instead (as a flag for instance)?
如果你的意思是,有没有办法让 pre-processor 将每个包含的文件都视为包含 pragma,无论它们是否有任何形式的 header 守卫那么没有,有在 C++ 中无法做到这一点。
理论上,您可以编写自己的 pre-processor 来执行此操作。然而,虽然这样pre-processor会相对简单,但我仍然认为在利益方面是一个不必要的复杂解决方案。
unless I add #pragma once reactively every time the problem pops up which seems "dirty" to me.
Is there a way to avoid the problem altogether?
有一个简单的方法可以pre-emptively 解决您已经提到的这个问题:在每个 header 文件的顶部添加 pragma 或传统宏 header 守卫。无需等待问题出现。这样做,你的烦恼就没有了。
我正在学习 C++,我遇到(并修复)了一个看起来非常 classic 的问题:
g++ main.cpp A.cpp B.cpp -o out
In file included from B.h:1,
from main.cpp:3:
A.h:1:7: error: redefinition of ‘class A’
1 | class A {
| ^
In file included from main.cpp:2:
通过快速研究(假设我理解正确),发生这种情况是因为 #include operation is not "idempotent"(我在这个问题中发现的一个术语)。
为了说明我的问题,我提出了一个最小的工作示例。
main.cpp
#include "A.h" #include "B.h" #include <iostream> int main () { std::cout << "Hello world" << std::endl; A a; B b(a); return 0; }
A.h
#include <iostream> class A { public: void test(); };
A.cpp
#include "A.h" void A::test () { std::cout << "test" << std::endl; }
B.h
#include "A.h" class B { public: B(A); };
B.cpp
#include "B.h" #include <iostream> B::B(A a){ a.test(); }
使用 g++ main.cpp A.cpp B.cpp
或更具体地说 g++ -c main.cpp
编译程序将失败并出现上述错误。
我了解到编译器 transcludes 在编译 main.cpp 时“A”的 header 两次(一次在 main.cpp:1 和一次在 B.h:1 在其自身包含在 main.cpp:2) 期间。实际上,编译器 'sees' 定义了 class A
两次,并认为我们定义了 A 两次。
我不明白的是包含守卫:
要解决此问题,可以在多次包含的文件顶部使用关键字:pragma once
:
A.h fixed with #pragma once
#pragma once #include <iostream> class A { public: void test(); };
允许程序顺利编译。
对我来说,这表明我应该在每个 header 开始时使用 #pragma once !!! 哪个不对?这是常见的做法吗?如果是这样,有没有办法在编译时执行此操作(例如作为标志)?
如果我不这样做,我可能不会使用 object A 作为 class A 的成员,也不会将其作为参数传递给 B(如在我的示例中的 B 的构造函数中),如果这样的话A 和 B 可以在另一个文件中单独使用;除非每次出现问题时我都反应性地添加 #pragma once
,这对我来说似乎是“肮脏的”。此外,我无法与任何人分享我的资源,因为担心他们会遇到我的两个 object 的情况,而不必自己在我的文件中添加 pragma once
。
我错过了什么?有没有办法完全避免这个问题?
您可以使用 #pragma once or the more "traditional" include guard.
如您所料,它应该存在于每个头文件中。
在此示例中,您提供了:
#pragma once
#include <iostream>
class A {
public:
void test();
};
不保证适用于所有环境。 (就像其他评论提到的那样。)以及 Circular Dependices.
但是使用两个预处理器指令:#ifndef
和 #endif
(包括守卫)
防止头文件被意外包含多次。
#ifndef A_H
告诉预处理器查找名为 A_H
的常量,该常量尚未使用 #define
指令创建。
现在,如果 A_H
常量尚未定义,则程序中将包含以下行:
class A {
public:
void test();
};
例如使用 ifndef
和 #endif
:
#ifndef A_H
#define A_H
class A {
public:
void test();
};
#endif
To me this suggest that I should start every header with #pragma once !!! Wich can't be right is it?
可能是对的。虽然理论上可能有点夸张。
Is it common practice?
是的,是的。如果我们 包括 使用宏 header 守卫的另一个选项到相同的实践中,这是相当普遍的。
If so, Is there a way to do that at compile time instead (as a flag for instance)?
如果你的意思是,有没有办法让 pre-processor 将每个包含的文件都视为包含 pragma,无论它们是否有任何形式的 header 守卫那么没有,有在 C++ 中无法做到这一点。
理论上,您可以编写自己的 pre-processor 来执行此操作。然而,虽然这样pre-processor会相对简单,但我仍然认为在利益方面是一个不必要的复杂解决方案。
unless I add #pragma once reactively every time the problem pops up which seems "dirty" to me.
Is there a way to avoid the problem altogether?
有一个简单的方法可以pre-emptively 解决您已经提到的这个问题:在每个 header 文件的顶部添加 pragma 或传统宏 header 守卫。无需等待问题出现。这样做,你的烦恼就没有了。