免责声明:
我对以下风格是否是“良好做法”的意见不感兴趣。我正在寻找解决问题的答案/方法。
问题:
我正在 cpp 文件中编译一个类。编译过程剥离了我认为“未使用”的方法定义。有什么办法可以防止这种情况发生吗? (参见下面的开发环境示例)
开发环境:
我目前正在使用 g++ --std=c++98
。一个完美的解决方案将适用于所有 c++98 标准编译器和更新版本。
示例:
example1.cpp
#include <stdio.h>
class Example1{
public:
void print(){printf("helloWorld");};
};
编译、汇编和链接该文件不会创建 print()
方法。 (g++ --std=c++98 example1.cpp main.cpp
,其中 main.cpp
只是调用打印方法。)
编译这个(没有链接,g++ --std=c++98 -S
)将输出:
example1.s
.file "example1.cpp"
.text
.ident "GCC: (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
这里显然没有生成print()
方法。
不好的解决方法
如果我在同一个文件中使用它,我可以让编译器生成方法(见下面的代码)。但是,我正在寻找更好的解决方案。也许编译器选项?
example1.cpp
#include <stdio.h>
class Example1{
public:
void print(){printf("helloWorld");};
};
// Create a function outside the class, that uses print().
// That way, print will be generated.
void foo(){
Example1 ex;
ex.print();
}
备注(编辑):
- 在类之外定义方法是不行的。
Example1
在main.cpp
中使用如下:
main.cpp
class Example1{
public:
void print();
};
int main(){
Example1 example;
example.print();
return 0;
}
最佳答案
简短的回答是“你不能使用标准 C++”。
较长的答案分为几个部分。
首先,您的变通办法并没有达到您认为的效果。
#include <stdio.h> class Example1{ public: void print(){printf("helloWorld");}; }; // Create a function outside the class, that uses print(). // That way, print will be generated. void foo(){ Example1 ex; ex.print(); }
这不会阻止编译器“删除”成员函数 Example1::print()
。没有什么可以阻止编译器在 foo()
中内联 Example1::print()
的调用,而不是(使用您的措辞)以某种形式生成该函数这(比如说)可以通过链接器解决。
其次,你的“main.cpp”
class Example1{ public: void print(); }; int main(){ Example1 example; example.print(); return 0; }
如果它与“example1.cpp”的任一版本在同一项目中使用,则会引入未定义的行为,因为类 Example1
的定义明显不同 - 一个定义了成员函数 print()
在类定义中,而另一个则没有。这打破了单一定义规则,因为您的程序有两个不同的类 Example1
定义。
如果您的第二个“example1.cpp”似乎“有效”(无论您如何评估),那么您就走运了。未定义行为的本质意味着它似乎可以工作。问题是,C++ 标准不提供任何此类保证 - 当行为未定义时,允许编译器做它喜欢做的事 - 你的代码可能看起来“有效”,或者它可能做一些完全不同的事情。
通常处理这种事情的方法是将类 Example1
的定义放在单独的头文件中,例如
// example1.h
#include <stdio.h>
class Example1{
public:
void print(){printf("helloWorld");};
};
然后将该 header 包含在所有需要它的源文件中。例如;
// example1.cpp
#include "example1.h"
void foo()
{
Example1 ex;
ex.print();
}
和
// main.cpp
#include "example1.h"
int main()
{
Example1 example;
example.print();
return 0;
}
以上两个源文件(example1.cpp 和 main.cpp)可以在同一个程序中安全使用。
由于函数 Example1::print()
是内联定义的,编译器可以自由地内联它。编译器仍然不需要内联,但允许这样做。这意味着,生成的目标文件或可执行文件不一定包含任何可识别(例如通过检查程序集)作为函数 Example1::print()
的内容。在您的示例中,main()
和 foo()
中可能只有调用 printf()
的代码,但没有明显的代码名为 Example1::print()
的函数。
正如另一个答案(您拒绝了,随后被删除)所说,防止内联的唯一方法是在类定义之外定义函数。该函数定义需要恰好位于项目的一个编译单元中。这允许编译器“生成”函数,但在技术上不需要它(智能编译器和链接器仍然允许“删除”该函数)。
关于c++ - 如果方法是在类内部定义的,则防止编译器删除方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59278553/