我何时以及为什么要使用 -fno-elide-constructors?
我正在学习 C++ 并且遇到了 -fno-elide-constructors
,下面我包含了手册页中的描述.
I'm learning C++ and I came across the -fno-elide-constructors
, below I have included the description from the man page.
-fno-elide-constructors
The C++ standard allows an implementation to omit creating a
temporary which is only used to initialize another object of the
same type. Specifying this option disables that optimization, and
forces G++ to call the copy constructor in all cases.
因此,使用此选项,我可以禁用这种特定类型的编译器优化.我有一个程序,它创建 2 个对象并将它们添加在一起并在使用 BASIC4TRACE 库调用每个函数时进行打印.我编译了同一个程序来测试两次使用此选项时函数调用的差异,一个有一个没有,给出了这个输出.
So with this option I am able disable this particular type of compiler optimization. I have a program that creates 2 objects and adds them together and prints when each of the function is called using using BASIC4TRACE library. I compiled the same program to test the difference in function calls while using this option twice, one with and one without, giving this output.
Without optimizations
BASIC4TRACE: (0x7fff7504a7c0)->Object(const char *)
BASIC4TRACE: (0x7fff7504a7d0)->Object(const char *)
BASIC4TRACE: (0x7fff7504a770)->Object(const char *)
BASIC4TRACE: op+(const Object&, const Object&)
BASIC4TRACE: (0x7fff7504a720)->Object()
BASIC4TRACE: (0x7fff7504a780)->Object(const Object&)
BASIC4TRACE: (0x7fff7504a720)->~Object()
BASIC4TRACE: op+(const Object&, const Object&)
BASIC4TRACE: (0x7fff7504a720)->Object()
BASIC4TRACE: (0x7fff7504a790)->Object(const Object&)
BASIC4TRACE: (0x7fff7504a720)->~Object()
BASIC4TRACE: (0x7fff7504a7f0)->Object(const Object&)
BASIC4TRACE: (0x7fff7504a790)->~Object()
BASIC4TRACE: (0x7fff7504a780)->~Object()
BASIC4TRACE: (0x7fff7504a770)->~Object()
BASIC4TRACE: (0x7fff7504a7e0)->Object(const Object&)
BASIC4TRACE: (0x7fff7504a7f0)->~Object()
BASIC4TRACE: (0x7fff7504a7e0)->~Object()
BASIC4TRACE: (0x7fff7504a7d0)->~Object()
BASIC4TRACE: (0x7fff7504a7c0)->~Object()
With optimizations
BASIC4TRACE: (0x7fffbfc8bbf0)->Object(const char *)
BASIC4TRACE: (0x7fffbfc8bc00)->Object(const char *)
BASIC4TRACE: (0x7fffbfc8bbb0)->Object(const char *)
BASIC4TRACE: op+(const Object&, const Object&)
BASIC4TRACE: (0x7fffbfc8bbc0)->Object()
BASIC4TRACE: op+(const Object&, const Object&)
BASIC4TRACE: (0x7fffbfc8bc10)->Object()
BASIC4TRACE: (0x7fffbfc8bbc0)->~Object()
BASIC4TRACE: (0x7fffbfc8bbb0)->~Object()
BASIC4TRACE: (0x7fffbfc8bc10)->~Object()
BASIC4TRACE: (0x7fffbfc8bc00)->~Object()
BASIC4TRACE: (0x7fffbfc8bbf0)->~Object()
如您所见,调用次数存在显着差异.所以我的问题是我什么时候会真正使用这个选项?是否存在此类优化导致问题的特定情况?我真的想不出我不希望我的代码尽可能优化的情况,所以我很难弄清楚这有什么好处.
As you can see there is a significant difference in the number of calls made. So my question is when would I actually use this option? Is there a specific case where this type of optimization causes problems? I can't really think of a situation where I wouldn't want my code to be optimized as much as possible so I am having a hard time trying to figure out what this is good for.
推荐答案
正如 Benjamin Lindley 对这个问题所评论的那样,如果您的程序依赖于复制构造函数的副作用,那么您的代码就会写得很糟糕.应始终编写复制构造函数,以便此类优化是安全的.不仅因为编译器可能会执行此类优化,还因为其他人类读者将很难理解发生了什么.
As Benjamin Lindley commented on the question, if your program relies on the side effects of copy constructors, your code is very badly written. Your copy constructors should always be written so that such optimisations are safe. Not only because the compiler may perform such optimisations, also because other human readers will otherwise have a very hard time understanding what is going on.
也就是说,该选项绝对有用.复制构造函数被省略的确切时间是不确定的,看似不相关的更改可能会改变复制省略是否发生.因此,-fno-elide-constructors
使 GCC 更具确定性,有时,这有助于调试,因为这意味着您可以不必担心通过添加调试打印语句(作为一个副作用发生在禁用复制省略).
That said, the option can still definitely be useful. Exactly when copy constructors are elided is unspecified, and seemingly irrelevant changes may change whether copy elision happens. Thus, -fno-elide-constructors
makes GCC more deterministic, and sometimes, that helps in debugging, as it means you can worry less about code that starts working just by adding debug print statements (which as a side effect happen to disable copy elision).
您可能想要使用 -fno-elide-constructors
的另一个原因是,如果您希望您的代码在执行较少复制省略的其他编译器上表现良好.如果无用的复制构造函数导致明显的速度减慢,您可以重新编写代码,使其无论副本是否被省略都很快.
Another reason you may want to use -fno-elide-constructors
is if you want your code to perform well on other compilers that perform less copy elision. If the useless copy constructors cause a noticeable slowdown, you can re-work the code so that it's fast regardless of whether copies get elided.
相关文章