C++ 有没有一种方法允许编译器优化对外部函数的多次调用?

C++ 有没有一种方法允许编译器优化对外部函数的多次调用?,c++,optimization,compile-time,C++,Optimization,Compile Time,我正在构造一个类似于C库的C++接口: extern "C" { typedef struct CFooStruct *CFoo; int CFoo_getLength(CFoo); // other functions } 目前我有 class MyFoo { CFoo foo; int len; public: MyFoo(CFoo foo) : foo(foo), len(CFoo_getLength(foo)) { } int length()

我正在构造一个类似于C库的C++接口:

extern "C" {

typedef struct CFooStruct *CFoo;

int CFoo_getLength(CFoo);

// other functions

}
目前我有

class MyFoo {
    CFoo foo;
    int len;
public:
    MyFoo(CFoo foo) : foo(foo), len(CFoo_getLength(foo)) { }

    int length() const { return len; } // inline function

    // other functions
};
长度在构造函数中检索并缓存,以便在紧循环中重复调用
MyFoo::length()
,而不会造成性能损失

直接使用C接口时,如果需要,可以手动检索一次长度,然后重复使用。如果不需要
CFoo
的长度,那么我们就永远不会调用
CFoo\u getLength()

<> P> C++接口意味着使用更简单,让用户只使用<代码>长度()/<代码>,而不需要考虑性能。上述实现的缺点是,它总是在创建每个
MyFoo
对象的过程中调用
CFoo\u getLength()
,而不管它是否将实际用于程序中

即使
MyFoo
的所有成员函数都是内联函数,我相信编译器不会优化对
CFoo_getLength()
的调用,因为它无法知道此函数没有副作用

问题:是否有办法实现此功能,以便只有在程序中实际使用长度时才会调用
CFoo\u getLength()
?(对于
MyFoo
对象,它从来不会被多次调用?)有没有一种方法可以让编译器优化
CFoo_getLength()
调用(如果它足够聪明,可以推断它不需要)


一种方法是在类中使用布尔标志,指示是否已检索到长度:

class MyFoo2 {
    CFoo foo;

    bool lenKnown = false;
    int len;
public:
    MyFoo2(CFoo foo) : foo(foo) { }

    int length() {
        if (!lenKnown) {
            len = CFoo_getLength(foo);
            lenKnown = true;
        }
        return len;
    }
};

但这是一个运行时解决方案,它使
MyFoo
更大,并导致
MyFoo::length()
中的额外计算。我想知道是否有编译时解决方案。

您可以应用
pure
函数属性将
CFoo\u getLength
标记为pure:

__attribute__ ((pure))
int CFoo_getLength(CFoo);

正如您所发现的,令我C++缺乏经验的惊讶的是,它允许gcc和clang优化您的原始代码。很好

如果
CFoo
的长度从直觉上来说确实是一个长度,那么您就可以去掉大小惩罚。@StoryTeller:哦,好的。那么,允许从其他地方链接实现的正确方法是什么?(这是否意味着当我编译单个
.cpp
文件时,其中包含
.o
s的标题,这很危险?@Ryan-我不能说是在线编译器。我目前实际上没有访问GCC的权限来进行验证。“我不是想在游行上泼冷水,我只是想指出OP需要做一些更严肃的测试,而不仅仅是对godbold的测试。”Ryan-关于你的简化问题。这并不危险。ODR方面涉及整个程序,而不是单个翻译单元。所以,只要你在最后把所有的东西都链接起来,你就可以去了。@Szabolcs-在联机编译器中不是这样的。我的全部观点是,它在godbolt(存在ODR违规的地方)中工作的事实并不表明它一般是否应该工作。但是如果是这样的话,在你自己的项目中,对你来说很好:)我正在阅读,似乎合适的属性实际上是
pure
(而不是
const
)。文档中说,“请注意,具有指针参数并检查指向的数据的函数不能声明为常量。”对
pure
@Szabolcs:Yikes没有这样的限制,我记错了。谢谢