是"可以轻易复制"足够与原始指针相同的传递约定?

时间:2015-06-02 01:01:07

标签: c++ pointers c++11 typetraits

我希望我的自定义Ptr<T>指针类生成等效的程序集作为原始指针T *。特别是,当传入和传出函数时,我希望它在寄存器中传递(就像T *那样),而不是在堆栈中传递。

通过实验,我发现至少gcc 4.9.2要求Ptr<T>trivially copyable,然后它为我尝试的所有情况(使用寄存器)生成与原始指针相同的程序集。如果它不是简单的可复制的,那么它使用堆栈,而不是寄存器。

它似乎不需要是standard layout type也不是trivial(即除了可以轻易复制之外还有一个简单的默认构造函数)。

我可以在所有平台上依赖于此,还是依赖于编译器?

对自定义类有什么建议(就上面的特征而言),所以它等同于生成的汇编代码的原始指针(当优化时)?

实际的Ptr<T>课程已在TrilinosTeuchos_PtrDecl.hppTeuchos_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>将在堆栈上传递。

0 个答案:

没有答案