2012-08-30 35 views
11

Trong C++ 11, có hai phiên bản của std::vector::resize():Nên (trong C++ 11) std :: vector :: thay đổi kích thước (size_type) làm việc cho mặc định constructible value_type int [4]?

void resize(size_type count); 
void resize(size_type count, const value_type& value); 

Tôi hiểu (theo đề nghị của một trong những ý kiến ​​để một trong những câu trả lời cho this question) rằng người đầu tiên đòi hỏi value_type là constructible mặc định, trong khi thứ hai yêu cầu nó phải được sao chép có thể xây dựng được. Tuy nhiên, (gcc 4.7.0)

using namespace std; 
typedef int block[4]; 
vector<block> A; 
static_assert(is_default_constructible<block>::value,";-("); // does not fire 
A.resize(100);            // compiler error 

Vì vậy, sự hiểu biết của tôi sai hoặc gcc là lỗi. Cái nào

+0

Sử dụng định nghĩa khối này: 'struct khối {int arr [4]; }; ' – PiotrNycz

+0

có thể trùng lặp của [lỗi trình biên dịch với C++ std :: vectơ của mảng] (http://stackoverflow.com/questions/12184828/compiler-error-with-c-stdvector-of-array) –

+0

@PiotrNycz: Trái với 'std :: array '? – ildjarn

Trả lời

10

Yêu cầu (23.3.6.3:10) trên vector.resize(n) được tốt được hình thành là T nên CopyInsertable, tức là sau đây cần được tốt được hình thành (23.2.1: 13):

allocator_traits<A>::construct(m, p, v); 

nơi A là loại phân bổ của vectơ, m là người cấp phát, p thuộc loại T *v thuộc loại T.

Như bạn có thể khám phá từ 20.6.8.2:5, đây là không hợp lệ với nhiều loại mảng trong trường hợp tổng quát vì nó là tương đương với gọi

::new(static_cast<void *>(p))block(v); 

đó là không hợp lệ với nhiều loại mảng (mảng không thể được khởi tạo bởi dấu ngoặc đơn).


Thực ra, bạn nói đúng rằng g ++ có lỗi; nó nên luôn luôn có thể làm việc xung quanh vấn đề này với CopyInsertable bằng cách cung cấp một cấp thích hợp, nhưng g ++ không cho phép điều này:

#include <vector> 

template<typename T, int n> struct ArrayAllocator: std::allocator<T[n]> { 
    void construct(T (*p)[n], T (&v)[n]) { 
     for (int i = 0; i < n; ++i) 
      ::new(static_cast<void *>(p + i)) T{v[i]}; 
    } 
}; 

int main() { 
    std::vector<int[4], ArrayAllocator<int, 4>> c; 
    c.resize(100); // fails 

    typedef ArrayAllocator<int, 4> A; 
    A m; 
    int (*p)[4] = 0, v[4]; 
    std::allocator_traits<A>::construct(m, p, v); // works 
} 

lỗi khác là trong tiêu chuẩn riêng của mình; 20.9.4.3:3 chỉ định std::is_default_constructible<T> tương đương với std::is_constructible<T>, trong đó 20.9.4.3:6 chỉ định std::is_constructible<T, Args...> làm tiêu chí chính xác trên T t(std::declval<Args>()...), có giá trị cho các loại mảng (như @Johannes Schaub-litb chỉ ra, các loại mảng có thể được khởi tạo với (zero-pack-expansion)). Tuy nhiên, 17.6.3.1:2 yêu cầu đối với DefaultConstructible ngoài ra, T() được định dạng đúng, không phải là trường hợp đối với loại mảng T nhưng không được kiểm tra bởi std::is_default_constructible.

+0

ai đó nên gửi một báo cáo lỗi ở đây. – Walter

+1

Đầu tiên tôi không hiểu được 'T t()' của bạn. Tôi đoán điều quan trọng cần đề cập đến đó là kết quả của một 'T t (mở rộng gói zero)'. Nếu không, thật khó để thấy được ý nghĩa của bạn bằng "ngữ cảnh biến định nghĩa". Nhưng 'T t (mở rộng gói zero)' * là * hợp lệ nếu 'T' là một kiểu mảng và kiểu phần tử có thể được khởi tạo giá trị. Chỉ 'T()' là không đúng định dạng nếu 'T' là một kiểu mảng. –

+0

@ JohannesSchaub-litb cảm ơn, trông giống như phần này là một lỗi trong định nghĩa của tiêu chuẩn của 'std :: is_default_constructible'. – ecatmur

0

Tôi đã tìm thấy cuộc thảo luận này sau khi tôi gặp sự cố tương tự với thay đổi kích thước() không hoạt động đối với loại có thể định cấu hình mặc định. Dường như việc thực thi vectơ gcc không chính xác.

FYI, tôi đã đệ đơn chống lại lỗi gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64147

Các vấn đề liên quan