カスタムクラスの加算演算子を実装しています。呼び出される関数/演算子は、フレンド関数でもメンバー関数でもないため、ベクトルにスカラー値を追加します(クラスは線形代数ベクトルクラスであると想定されています)。内部的には、この関数はクラスの加算演算子を呼び出し、次に同じクラスの複合加算を呼び出します。
以下は、クラスの宣言の関連部分(これはテンプレートクラスです)と、コンストラクター、非メンバー関数/演算子、および複合加算演算子の実装です(加算演算子は以下に続き、「問題」を示します。 ")。
template<class T>
class Vector {
public:
Vector(const unsigned long length); // Default ctor
Vector(const Vector<T>& vec); // Copy ctor
template<class S>
Vector<T> operator +(const S& scalar);
template<class S>
Vector<T>& operator +=(const S& scalar);
private:
unsigned long mLen;
T* mData;
};
template<class T, class S>
Vector<T> operator +(const S& scalar, const Vector<T>& vec);
// Implementation of ctors
template<class T>
Vector<T>::Vector(const unsigned long length) {
mLen = length;
mData = new T[length];
}
template<class T>
Vector<T>::Vector(const Vector<T>& vec) {
mLen = vec.mLen;
std::copy_n(vec.mData, vec.mLen, mData);
}
template<class T, class S>
Vector<T> operator +(const S& scalar, const Vector<T>& vec) {
return vec + scalar;
}
template<class T> template<class S>
Vector<T>& Vector<T>::operator +=(const S& scalar) {
for(unsigned long i = 0; i < mLen; ++i) {
mData[i] += scalar;
}
return *this;
}
すでに述べたように、実装は複合代入演算子に基づいています。すべての演算子は、結果ワイズ、意図したとおりに機能しているように見える、しかし、私は複合代入演算の結果を返す際に直接コピーコンストラクタが呼び出され、私はその理由を理解することはできません。説明については、次の例を参照してください。
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this); // Normal copy ctor call
return result += scalar; // Here the copy ctor is invoked again!!!
}
// Implementation of the addition operators
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this); // Normal copy ctor call
result += scalar;
return result; // Here the copy ctor is NOT invoked
}
main.cpp
例では、次の可能性
int main(int argc, const char* argv[]) {
Vector<T> vec(10);
1 + vec;
}
ここで、加算演算子の最初の実装が使用されると、コピーコンストラクターがreturnステートメントで呼び出されます(上記の行に加えて、明らかに完全に理にかなっています)。演算子が2番目の方法で実装されている場合、上記の行で明示的に呼び出された場合、コピーコンストラクターは1回だけ呼び出されます。
私はXCode11.3.1を使用しています(Macでは明らかに)。この問題についてさらに情報が必要な場合はお知らせください。誰かがここで光を当てることができれば、私は感謝するでしょう。
以来operator+=
戻って参照、return文は関数の戻り値には、この参照値をコピーする必要があります。コンパイラーがコピーコンストラクターへのこの呼び出しを排除するために使用できる値はありません。
あなたの最初の例は同等です
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this);
Vector<T> &ans = (result += scalar); // (Parens included for clarity)
return ans;
}
これにより、コンパイラがreturnステートメントでコピーコンストラクタを呼び出さなければならない理由がより明確になります。
2番目の例では、ローカルをresult
直接返すため、コピーコンストラクターの呼び出しは省略されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加