我正在包装一个现有的库而不会引入太多的开销,使得包装器库可以像现有的一样快地运行。我这样做是为了使接口(语法)与我的旧代码兼容。
比如说,现有的类叫做BASE,它是模板类。我把它包装成如下。
template<class T>
class Wrapper{
public:
Wrapper() : base(){};
/* ... */
Wrapper<T> dosomething ( const Wrapper<T>& a )
{
Wrapper<T> output;
output.base = CallExistingClass(a.base);
return output;
}
private:
BASE<T> base;
};
对于没有返回类型的任何成员函数,使用this或* this生成非常有效的代码。但是,当返回类型
Wrapper<T>
是必需的,调用包装库总是慢5-10倍。由于它只是一个包装类,我需要的所有操作都是提取成员变量“base”(例如“a.base”),使用现有类中的函数对a.base执行某些操作,然后将结果传输到“输出” .base“并返回”输出“。
我必须确保包装类匹配旧代码的旧语法,返回指针不是一个选项。我能想到的解决方法是使用静态变量返回引用。例如,声明这种方式并通过引用返回
Wrapper<T>& dosomething ( const Wrapper<T>& a)
{
static Wrapper<T> output;
output.base = CallExistingClass(a.base);
return output;
}
我想知道是否有更快的方法来做到这一点而不会产生开销/临时?查看转发任何有用的评论。
一个简单的优化是使用初始化而不是赋值,例如,
template <class... U>
Wrapper(U&&... args) : base(std::forward<U>(args)...) {} // forward constructor
Wrapper<T> dosomething ( const Wrapper<T>& a )
{
Wrapper<T> output{CallExistingClass(a.base)};
return output;
}
由于copy elision,这不仅可以避免不必要的值初始化,还可以避免任何复制操作。
另外,要在对象dosomething
上调用a
,对于当前声明,您应该创建一个额外的对象(比如w
),并以w.dosomething(a)
的形式调用它。为了改善这一点,有两种方法。
(1)注意dosomething
的效果不依赖于数据成员,因此您可以将其声明为static
,例如:
static Wrapper<T> dosomething ( const Wrapper<T>& a )
{
//...
}
然后你可以在Wrapper<T>::dosomething(a)
的形式使用它,而无需创建额外的对象。
(2)此外,您可以使用数据成员而不是参数,例如
Wrapper<T> dosomething const ()
{
Wrapper<T> output{CallExistingClass(base)};
return output;
}
并以a.dosomeghing()
的形式称呼它。