2011-12-11 121 views
11

比方說,我有帶有const成員的結構向量?

#include <string> 
#include <vector> 
using namespace std; 

struct Student 
{ 
    const string name; 
    int grade; 
    Student(const string &name) : name(name) { } 
}; 

如何,然後,保持學生的載體?

int main() 
{ 
    vector<Student> v; 

    // error C2582: 'operator =' function is unavailable in 'Student' 
    v.push_back(Student("john")); 
} 

有甚至辦法做到這一點,或者我要所有的學生在堆上分配,並存儲一個指向他們每個人的呢?

+0

這似乎是編譯並與VC 2010鏈接。您能提供有關您的環境的更多信息嗎?這是一個完整的測試用例,是否會再現編譯失敗? – DRH

+0

@DRH:我在VC 2008上,對不起。是的,這是整個測試案例。 – Mehrdad

+0

雖然對於其他操作,您將需要賦值運算符,但我想不出任何可能的原因,爲什麼'push_back'會有這個要求......然後,可能是實現檢查'Assignable'要求。 –

回答

7

你不能。您的類型違反了標準容器的「可分配」要求。

ISO/IEC 14882:2003 23.1 [lib.container.requirements]/3:

的類型存儲在這些組件必須滿足CopyConstructible 類型(20.1.3)的要求的對象,並Assignable類型的附加要求。

從表64(Assignable要求):

在表64中,T是用於實例化容器的類型,tT的值,並且u是(可能const的值)T

表達式:t = u;返回類型:T;後置條件:t相當於u

在理論上,std::vector相當於可以選擇做破壞,在所有情況下拷貝構造,但是這不是已經選擇了合同。如果不需要重新分配,那麼對於像vector::operator=vector::assign這樣的東西使用包含類型的賦值運算符可能會更有效。

+0

呵呵......所以即使我從不指定任何東西,它也需要賦值。不知道。 – Mehrdad

+0

@Philipp:實際上,重新分配時,矢量不分配任何東西。它通常只複製或移動構建新範圍,然後刪除舊範圍。 –

+0

嗯......爲什麼'vector'執行拷貝分配呢?難道它不能複製施工+破壞,而不是使用'operator ='? – Mehrdad

8

簡單的答案是:你不能。如果您有const成員變量,那麼編譯器不能提供默認的複製分配操作符。但是,std::vector提供的許多操作都需要進行分配,因此需要(公共)複製分配操作員。

的選項有:

  1. nameconst
  2. 寫下您自己的複製分配操作員,並想辦法處理「複製」const成員。
1

向量元素必須是可複製分配的,您的Student結構不是因爲const成員。只需使用string name而不是const string name。 除非你有特定的要求,否則類中的常量成員很少用到。如果您想防止對成員進行更改,請將其設置爲私人並添加公共的getter函數。

3

A vector通常需要移動元素。每當調用push_back()時向量需要增長時,它會重新分配內存以保持自身連續性,並將所有現有元素複製到新空間中。另外,如果您撥打insert()remove()元素,則必須移動 。對於vector能夠做所有元素必須是可複製分配的,這意味着您存儲在向量中的類型必須具有已定義的賦值運算符。

通常,如果您定義了一個類,編譯器將爲您生成該類的賦值運算符。但是,有些情況下編譯器無法做到這一點。其中一種情況是類有常量成員(請注意,指向常量的指針可以)。

因此,在你的情況下,問題是const string name。它可以防止編譯器生成operator=(),這反過來會阻止編譯vector,即使您自己實際上並未實際使用其元素的賦值。

一個解決方案是使name非常量。另一種是以某種合理的方式編寫自己的Student::operator=()。正如你所指出的,第三種方法是使用指針向量而不是對象向量。但是你必須處理他們的分配和解除分配。

P.S.編譯器無法生成operator=的另一種情況是當您的類具有引用的成員時。