Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这样的继承对性能有什么影响?_C++_Inheritance_Directxmath - Fatal编程技术网

C++ 这样的继承对性能有什么影响?

C++ 这样的继承对性能有什么影响?,c++,inheritance,directxmath,C++,Inheritance,Directxmath,我正在使用DirectXMath(或XNAMath)库(在WindowsSDK的DirectXMath.h头中定义),因为它看起来性能非常好,并且提供了物理和渲染所需的一切。但是我发现它非常冗长(在任何地方使用XMStoreFloatX和XMLoadFloatX都很累人) 我试图让它更易于操作,并想出了在赋值运算符/转换运算符中隐藏存储/加载的想法。由于这两个函数都必须是成员函数,因此我以以下代码为例: struct Vector2F : public DirectX::XMFLOAT2 {

我正在使用DirectXMath(或XNAMath)库(在WindowsSDK的DirectXMath.h头中定义),因为它看起来性能非常好,并且提供了物理和渲染所需的一切。但是我发现它非常冗长(在任何地方使用XMStoreFloatX和XMLoadFloatX都很累人)

我试图让它更易于操作,并想出了在赋值运算符/转换运算符中隐藏存储/加载的想法。由于这两个函数都必须是成员函数,因此我以以下代码为例:

struct Vector2F : public DirectX::XMFLOAT2 {
    inline Vector2F() : DirectX::XMFLOAT2() {};
    inline Vector2F(float x, float y) : DirectX::XMFLOAT2(x, y) {};
    inline Vector2F(float const * pArray) : DirectX::XMFLOAT2(pArray) {};

    inline Vector2F(DirectX::XMVECTOR vector) {
        DirectX::XMStoreFloat2(this, vector);
    }
    inline Vector2F& __vectorcall operator= (DirectX::XMVECTOR vector) {
        DirectX::XMStoreFloat2(this, vector);
        return *this;
    }

    inline __vectorcall operator DirectX::XMVECTOR() {
        return DirectX::XMLoadFloat2(this);
    }
};
如您所见,它复制了XMFLOAT2的公共接口,并为XMVECTOR添加了构造函数、赋值运算符和转换,XMVECTOR是用于计算的SIMD类型DirectXMath。我打算对DirectXMath提供的每个存储结构都这样做

对于一个数学图书馆来说,性能是一个非常重要的因素,因此我的问题是::这样一个继承对性能有什么影响?与库的正常使用相比,是否生成了任何额外的代码(当然假设完全优化)

直观地说,我会说生成的代码应该与我使用verbose变量时完全相同,没有这些方便的运算符,因为我基本上只是重命名结构和函数。但也许有些方面我不知道


另外,我有点担心赋值运算符的返回类型,因为它添加了额外的代码。省略返回的引用以优化它是否是一个好主意?

如果您发现这对于您的口味来说有点过于冗长,请查看。特别是
Vector2
类:

struct Vector2 : public XMFLOAT2
{
    Vector2() : XMFLOAT2(0.f, 0.f) {}
    explicit Vector2(float x) : XMFLOAT2( x, x ) {}
    Vector2(float _x, float _y) : XMFLOAT2(_x, _y) {}
    explicit Vector2(_In_reads_(2) const float *pArray) : XMFLOAT2(pArray) {}
    Vector2(FXMVECTOR V) { XMStoreFloat2( this, V ); }
    Vector2(const XMFLOAT2& V) { this->x = V.x; this->y = V.y; }
    explicit Vector2(const XMVECTORF32& F) { this->x = F.f[0]; this->y = F.f[1]; }

    operator XMVECTOR() const { return XMLoadFloat2( this ); }

    // Comparison operators
    bool operator == ( const Vector2& V ) const;
    bool operator != ( const Vector2& V ) const;

    // Assignment operators
    Vector2& operator= (const Vector2& V) { x = V.x; y = V.y; return *this; }
    Vector2& operator= (const XMFLOAT2& V) { x = V.x; y = V.y; return *this; }
    Vector2& operator= (const XMVECTORF32& F) { x = F.f[0]; y = F.f[1]; return *this; }
    Vector2& operator+= (const Vector2& V);
    Vector2& operator-= (const Vector2& V);
    Vector2& operator*= (const Vector2& V);
    Vector2& operator*= (float S);
    Vector2& operator/= (float S);

    // Unary operators
    Vector2 operator+ () const { return *this; }
    Vector2 operator- () const { return Vector2(-x, -y); }

    // Vector operations
    bool InBounds( const Vector2& Bounds ) const;

    float Length() const;
    float LengthSquared() const;

    float Dot( const Vector2& V ) const;
    void Cross( const Vector2& V, Vector2& result ) const;
    Vector2 Cross( const Vector2& V ) const;

    void Normalize();
    void Normalize( Vector2& result ) const;

    void Clamp( const Vector2& vmin, const Vector2& vmax );
    void Clamp( const Vector2& vmin, const Vector2& vmax, Vector2& result ) const;

    // Static functions
    static float Distance( const Vector2& v1, const Vector2& v2 );
    static float DistanceSquared( const Vector2& v1, const Vector2& v2 );

    static void Min( const Vector2& v1, const Vector2& v2, Vector2& result );
    static Vector2 Min( const Vector2& v1, const Vector2& v2 );

    static void Max( const Vector2& v1, const Vector2& v2, Vector2& result );
    static Vector2 Max( const Vector2& v1, const Vector2& v2 );

    static void Lerp( const Vector2& v1, const Vector2& v2, float t, Vector2& result );
    static Vector2 Lerp( const Vector2& v1, const Vector2& v2, float t );

    static void SmoothStep( const Vector2& v1, const Vector2& v2, float t, Vector2& result );
    static Vector2 SmoothStep( const Vector2& v1, const Vector2& v2, float t );

    static void Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result );
    static Vector2 Barycentric( const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g );

    static void CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result );
    static Vector2 CatmullRom( const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t );

    static void Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result );
    static Vector2 Hermite( const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t );

    static void Reflect( const Vector2& ivec, const Vector2& nvec, Vector2& result );
    static Vector2 Reflect( const Vector2& ivec, const Vector2& nvec );

    static void Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result );
    static Vector2 Refract( const Vector2& ivec, const Vector2& nvec, float refractionIndex );

    static void Transform( const Vector2& v, const Quaternion& quat, Vector2& result );
    static Vector2 Transform( const Vector2& v, const Quaternion& quat );

    static void Transform( const Vector2& v, const Matrix& m, Vector2& result );
    static Vector2 Transform( const Vector2& v, const Matrix& m );
    static void Transform( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray );

    static void Transform( const Vector2& v, const Matrix& m, Vector4& result );
    static void Transform( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray );

    static void TransformNormal( const Vector2& v, const Matrix& m, Vector2& result );
    static Vector2 TransformNormal( const Vector2& v, const Matrix& m );
    static void TransformNormal( _In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray );

    // Constants
    static const Vector2 Zero;
    static const Vector2 One;
    static const Vector2 UnitX;
    static const Vector2 UnitY;
};

// Binary operators
Vector2 operator+ (const Vector2& V1, const Vector2& V2);
Vector2 operator- (const Vector2& V1, const Vector2& V2);
Vector2 operator* (const Vector2& V1, const Vector2& V2);
Vector2 operator* (const Vector2& V, float S);
Vector2 operator/ (const Vector2& V1, const Vector2& V2);
Vector2 operator* (float S, const Vector2& V);
DirectXMath如此冗长的主要原因首先是为了让程序员在“溢出到内存”时非常清楚,因为这往往会对SIMD代码的性能产生负面影响。当我从XNAMath迁移到DirectXMath时,我曾考虑过添加一些类似于我用于“SimpleMath”的隐式转换,但我想确保任何这样的“C++魔术”都是选择性加入的,对于性能敏感的开发人员来说,这绝不会让人感到意外。SimpleMath的作用也有点像训练轮,可以更轻松地移植不支持对齐的现有代码,并随着时间的推移将其变形为更为SIMD友好的代码

SimpleMath(以及您的包装器)的真正性能问题是,每个函数实现都必须围绕相当少量的SIMD进行显式加载和存储。理想情况下,在优化的代码中,它们都会被合并,但在调试代码中,它们总是存在的。要从SIMD中获得真正的性能优势,您需要在每个加载和存储对之间长时间运行寄存器内SIMD操作


另一个含义是,像
Vector2
或您的
Vector2F
这样的包装器传递的参数永远不会特别有效。
XMVECTOR
\uuum128
的类型定义而不是结构,而
FXMVECTOR
GXMVECTOR
HXMVECTOR
CXMVECTOR
的存在是为了尝试优化所有可能的调用约定场景,并在最佳情况下获得寄存器传递行为(如果事情没有内联)。请参阅。使用
Vector2
可以做的最好的事情就是一致地传递
const&
,以最小化临时性和堆栈副本。

我想您会发现,在优化的代码中,性能损失将为零。如果不使用返回值,编译器极有可能优化出
return*this;
。这是编译器非常熟悉的一种常用习惯用法。您有两种隐式转换:1)从XMVECTOR到XMVECTOR,2)到XMVECTOR。这很有可能造成歧义。不要这样做(不要使用Vector2F)。@DieterLücking当然我有可能将这些转换显式化,但这段代码的目的是减少处理DirectXMath的冗长。对于稍微习惯DirectXMath的人来说,可能的歧义实际上应该不是问题。我将重新考虑这一点,稍后决定是否明确转换。