2012-09-30 70 views
0

的高效/快速複製對於定製使用,我已將std::vector繼承自定義class Vector。對於我的要求publicinheritance is ok標準容器如std :: vector

其中一個目的是避免複製矢量數組的多次,所以我決定這個自定義類是「所有權」的基礎。

Vector<A> vA1(100); // vA1 is allocated A[100] 
Vector<A> vA2 = vA1; // vA2 refers to original A[100] and ... 
        // ... vA1 is now blank which is expected 

這是它是如何對C++ 03實現的:

template<typename T> 
struct Vector : std::vector<T> 
{ 
    // ... other constructors 

    Vector (const Vector &copy) // copy constructor 
    { 
    this->swap(const_cast<Vector&>(copy)); // <---- line of interest 
    } 
    // 'operator =' is TBD (either same as above or unimplemented) 
}; 

我是不是違反任何語言規則/特徵/慣例?這段代碼有什麼不好的地方?

編輯:我在下面的答案中添加了我的新方法(這裏是它的工作demo)。

+2

如果你要重載'OPER ator =',它應該與'='具有相同的語義。你的不是。同上你的拷貝構造函數。 –

+0

@DavidSchwartz,是的,我還沒有決定'operator ='並更新了這個問題。目前,主要關注的是複製。 – iammilind

+0

爲什麼'const Vector&copy'和演員?爲什麼不只是「Vector(Vector&victim)」? –

回答

1

隨着評論/回答的洞察力,我意識到我目前的做法不是一個好主意來處理事情。
我想出了一個設計更改的地方,我嘗試使用swap()方法來模擬「移動」操作(在此情況下認爲它們可以互換)。這裏

/* 
    * An empty CRTP base class for the classes which are allowing move sematics (effectively swap) 
    * A given class `X` must implement `void swap(X&);` method for the movement (i.e. content swapping) 
    * For example, `X` is deriving this class (i.e. `class X : public Movable<X> ...`) 
    * ... below is an illustration for how to transfer contents of an `X` object to another 
    * `X o1; ... X o2(o1.move()); // contents of o1 is now moved to o2` 
    */ 
    template<typename Derived> 
    class Movable 
    { 
    /* 
    * Empty constructor for normal behavior 
    */ 
    public: Movable() 
      {} 

    /* 
    * Copy constructor which does nothing; without this compiler errors out ! 
    */ 
    public: Movable (const Movable &copy) 
      {} 

    /* 
    * Move constructor which will effectively call `Derived::swap()` method 
    * After this, the contents of the object will be moved to each other 
    * For syntactic sugar, it has been made `explicit` 
    */ 
    public: explicit Movable (Movable &orig) 
      { 
       (*this)(orig); 
      } 

    /* 
    * Moving while Not initializing object, one need to use `operator()` and not `operator =` 
    * If `operator =` is used then simply `move()` part will not happen; i.e. below 2 are same: 
    * `obj1 = obj2.move();` and `obj1 = obj2;` 
    */ 
    public: void operator() (Movable &orig) 
      { 
       static_cast<Derived*>(this)->swap(static_cast<Derived&>(orig)); 
      } 
    /* 
    * This method is called from `Derived` class when move sematics is intended 
    */ 
    public: Movable& move() 
      { 
       return *this; 
      } 
    }; 

它應該怎樣進行部署:

對於任何類或容器,它希望以做出更加快速複製(即通過交換移動)應該繼承以下的類(直接從真實的文件複製粘貼) :

template<typename T> 
struct Vector : std::vector<T>, 
       Movable<Vector<T> > // inherit as CRTP base 
{ 
    // ... other methods 
    typedef Movable<Vector<T> > Movable_; 
    Vector (Movable_ &orig) : Movable_(orig) {} // Declare a constructor 
}; 

這裏它應該如何使用:

Vector<A> vA1(100); // vA1 is allocated A[100] 
Vector<A> vA2 = vA1; // normal copying (no change) 
vA2 = vA1; // normal assignment (no change) 
Vector<A> vA3(vA1.move()); // <------- "moves" contents from 'vA1' to 'vA3' 
vA1(vA2.move()); // <------- "moves" contents from 'vA2' to 'vA1' 
vA2 = vA3.move(); // normal copying from 'vA3' to 'vA2' ('vA3' unaffected) 
4

我認爲你正在尋找的是移動語義。

Vector<A> vA1(100); // vA1 is allocated A[100] 
Vector<A> vA2 = std::move(vA1); // vA2 refers to original A[100] and ... 
       // ... vA1 is now blank which is expected 

如果你的編譯器沒有移動語義支持,我會建議你使用智能指針或看看boost::move可以在預先C++ 11個編譯模擬移動語義..

std::shared_ptr<Vector<A>> vA1(new Vector<A>(100)); // vA1 is allocated A[100] 
std::shared_ptr<Vector<A>> vA2 = vA1; // vA2 refers to original A[100] and ... 
vA1.reset(); 
       // ... vA1 is now blank which is expected 

或者更簡單:

Vector<A> vA1(100); // vA1 is allocated A[100] 
Vector<A> vA2; 
vA1.swap(vA2);// vA2 refers to original A[100] and ... 
       // ... vA1 is now blank which is expected 
3

你真的應該看看使用C++ 11:所有的標準容器是可移動的,並因此類似在很多情況下你的語義,吶只有當知道所有權可以轉讓時纔是如此。更確切地說,容器在從函數返回對象或使用臨時構造或分配對象時被移動而不是被複制。試圖以某種方式複製這種機制在某些情況下幾乎肯定會產生意想不到的行爲。

在C++ 11中,可移動語義被集成到語言和函數中,包括構造函數和賦值,可以被重載以根據對象是否可移動而表現不同。

2

你的代碼,打破了支持常量,正確性的約定:

const Vector<int> foo(12); 
const Vector<int> bar(foo); // UB. 
some_function_that_takes_Vector_by_value(bar); // UB. 

你可能會說,「但沒有人會創造一個Vector例如const,所以UB永遠不會發生」。在這種情況下,您至少可以讓您的副本採用非const引用,以遵循約定,即函數不應修改const&參數所採用的對象。

即便如此,我個人更希望要求用戶通過顯式交換來「開啓」速度,而不是爲他們創建像這樣的陷阱。我也更喜歡沒有任何拷貝,而不是像普通拷貝那樣。如果人們不得不記住Vector實際上不能被複制,那麼他們不應該使用複製語法來不復制它。

C++ 03中不必要拷貝的問題不是一個新問題,而且它不需要一個新穎的解決方案。許多C++程序員已經知道如何利用swap和複製elision,而那些不知道如何避免不必要拷貝的人最好是學習以正常的方式來完成它,而不是學習以一種獨特的方式來實現它具體的類。