我正在使用一個名為Point3D如下所示的類的遺留應用程式......
template <class T>
class Point3D final
{
T values[3];
public:
Point3D();
Point3D(T x, T y, T z);
explicit Point3D(const T value);
Point3D(const Point3D& point);
explicit Point3D(const Point2D<T>& point);
~Point3D();
};
這個類在很多地方都被用作vector<Point3D<double>>. 矢量的大小是 > 10^5。此外,遺留代碼將此向量作為值傳遞并按值回傳。這使得應用程式非常慢。同樣在很多地方,我們有類似的代碼,如下所示......
for(auto i: n){ // This loop runs for 10^4 times
Point3D<double> vpos;
vpos[X_COORDINATE] = /*Some calculation*/;
vpos[Y_COORDINATE] = /*Some calculation*/;
vpos[Z_COORDINATE] = /*Some calculation*/;
Positions.push_back(vpos);
}
為了提高性能,我計劃修改Point3D要使用的類,move semantics如下所示...
template <class T>
class Point3D final {
T* values;
public:
Point3D() {
values = new T[3];
}
Point3D(T x, T y, T z) {
values = new T[3];
}
explicit Point3D(const T value) {
values = new T[3];
}
Point3D(const Point3D& point) {
values = new T[3];
}
~Point3D() {
delete[] values;
}
T operator [] (qint64 coordinate) const { return values[coordinate]; }
T& operator [] (qint64 coordinate) { return values[coordinate]; }
Point3D& operator = (const Point3D& point) {
...
return *this;
}
Point3D(Point3D&& other) noexcept : values(other.values)
{
other.values = nullptr;
}
Point3D& operator=(Point3D&& other) noexcept
{
using std::swap;
swap(*this, other);
return *this;
}
};
我是新手move semantics,請讓我知道任何其他提高性能的方法。謝謝
uj5u.com熱心網友回復:
此外,遺留代碼將此向量作為值傳遞并按值回傳。這使得應用程式非常慢。
一般來說,您建議的修改會使情況變得更糟。如果是像 . 這樣的簡單型別,復制或移動原件的成本Point3D非常小。它只會復制三個值。如果是復雜型別,那么正如另一個答案所暗示的那樣,洗掉宣告的解構式和復制建構式將導致移動語意自動正確實作。(這也稱為“零規則”,讓所有特殊成員函式都隱式實作。)TdoubledoubleT
如果您的問題是該型別向量的多個副本,那么該型別的移動語意將對您毫無幫助。復制向量仍然需要復制所有元素。搬家是不夠的。
您需要在這些向量的使用站點調整您的代碼。例如,如果您按值傳遞這樣的向量:
void f(vector<Point3D<double>>);
void g() {
vector<Point3D<double>> v;
// fill v
f(v);
}
然后這將制作一個不必要的向量副本。這是不必要的,因為在呼叫inv之后不再需要資料。所以它可以移動而不是復制到函式中:fg
void g() {
vector<Point3D<double>> v;
// fill v
f(std::move(v));
}
這將移動矢量,而不是Point3D<double>。移動向量是一個常量時間操作,無論是否為元素型別實作了移動語意。它不會復制或移動任何元素。
如果 howeverv的狀態用在g呼叫之后,那么你不能直接使用移動??語意,因為移動語意會導致狀態丟失。在那種情況下,您需要重新考慮函式的設計并考慮例如通過const參考傳遞。
(但是請注意,如果您回傳向量,則不應使用。例如,應該使用。Move 隱含在 return 陳述句中,僅按名稱直接回傳區域變數,并且進行隱式呼叫將抑制復制省略,這在某些情況下會消除復制/完全移動。)std::movereturn std::move(v);return v;std::move
uj5u.com熱心網友回復:
移動建構式和賦值std::vector 不關心包含的型別,所以你根本不需要改變你的類。您需要做的是修復您對std::vector.
您不需要在此處使用動態分配,并且可以通過洗掉代碼來獲得移動語意。但是,移動 s 沒有任何好處double,您只會受益于 usingPoint3D<std::string>或類似的東西。
template <class T>
class Point3D final
{
T values[3];
public:
Point3D();
Point3D(T x, T y, T z);
explicit Point3D(const T value);
explicit Point3D(const Point2D<T>& point);
};
因為您指定了復制建構式,所以您的型別沒有默認的移動建構式。默認值會做正確的事情,所以你不需要指定特殊的成員函式。
uj5u.com熱心網友回復:
首先,在您展示的示例中,您可以簡單地將 push_back 替換為 emplace_back ,如下所示:
for(auto i : n)
{ // This loop runs for 10^4 times
auto x_coord = /*Some calculation*/;
auto y_coord = /*Some calculation*/;
auto z_coord = /*Some calculation*/;
Positions.emplace_back(x_coord,y_coord,z_coord);
}
這會在適當的位置構造 Point3D 實體,因此無需進行移動或復制。
對于更現代的 C ,我建議您使用 std::array 而不是 ac 樣式陣列。此外,您還可以使用默認的移動和復制建構式,而不必顯式移動或復制陣列中的每個元素。Point3D 類可能如下所示:
#include <array>
template <typename T>
class Point3D
{
std::array<T,3> values;
public:
Point3D()= default;
Point3D(const T& x, const T& y, const T& z):
values{x,y,z}
{}
// Rest of Class ...
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/533811.html
標籤:C C 11移动语义
