我希望我的自定义Ptr<T>
指针类生成等效的程序集作为原始指针T *
。特别是,当传入和传出函数时,我希望它在寄存器中传递(就像T *
那样),而不是在堆栈中传递。
通过实验,我发现至少gcc 4.9.2要求Ptr<T>
为trivially copyable,然后它为我尝试的所有情况(使用寄存器)生成与原始指针相同的程序集。如果它不是简单的可复制的,那么它使用堆栈,而不是寄存器。
它似乎不需要是standard layout type也不是trivial(即除了可以轻易复制之外还有一个简单的默认构造函数)。
我可以在所有平台上依赖于此,还是依赖于编译器?
对自定义类有什么建议(就上面的特征而言),所以它等同于生成的汇编代码的原始指针(当优化时)?
实际的Ptr<T>
课程已在Trilinos和Teuchos_PtrDecl.hpp的Teuchos_Ptr.hpp中实施。它具有Debug和Release版本(使用ifdefs),Debug版本检查(即引发一个很好的例外)悬空指针(例如,如果你使用Ptr<T>
获得RCP<T>::ptr()
实例,其中RCP
是Trilinos中的引用计数指针)。在发布模式中,Ptr<T>
应该与原始指针一样快,这就是我在这个问题中所关注的问题。我们的想法是在调试模式下测试代码以获取所有可能的用户输入,如果它没有触发任何调试异常,则可以使用相同的生成运行代码切换到Release版本,并且它具有原始指针性能。在发布模式下,该类等同于:
enum ENull { null };
template<class T>
class Ptr {
public:
// Constructors from other types
inline Ptr(ENull null_in=null) : ptr_(0) {}
inline explicit Ptr(T *ptr) : ptr_(ptr) { }
template<class T2> inline Ptr(const Ptr<T2>& ptr) : ptr_(ptr.get()) {}
// We want Ptr to be TriviallyCopyable, so we must use the default copy
// constructor and assingment, default move constructor and assignment and
// default destructor.
~Ptr() = default;
inline Ptr(const Ptr<T>&) = default;
Ptr<T>& operator=(const Ptr<T>&) = default;
inline Ptr(Ptr&&) = default;
Ptr<T>& operator=(Ptr&&) = default;
inline T* operator->() const { return ptr_; }
inline T& operator*() const { return *ptr_; }
inline T* get() const { return ptr_; }
inline T* getRawPtr() const { return get(); }
inline const Ptr<T> ptr() const { return *this; }
private:
T *ptr_;
};
以下是使用gcc 4.8.2编译的完整测试代码+生成的程序集:https://gist.github.com/certik/9598dc3f01608e350efd
这个类是可复制的标准布局类型,但不是简单的默认构造(因此不是简单的或POD)。可以添加例如:
public:
int i;
使它不是标准布局类型(但仍然可以轻易地复制)并通过检查汇编代码,它仍然具有与原始指针相同的程序集。另一方面,如果一个人摆脱了平凡的可复制特征(例如通过添加一些虚函数,或实现一些复制或移动构造函数或赋值),那么程序集将不相等(而是Ptr<T>
将在堆栈上传递。