2014-10-28 15 views
6

Tôi đang trong quá trình thiết kế một số lớp cho mảng động (ví dụ như std :: vector). Lý do tôi không muốn sử dụng std :: vector là vì các chương trình C++ của tôi thường được sử dụng như một thư viện được gọi là từ C/C++/Fortran/Delphi và do đó lấy mảng vào làm con trỏ. Vì lý do an ninh, một std :: vector không thể ăn cắp một con trỏ tại thời điểm xây dựng. My Array1D có thể hoạt động như một std :: vector nhưng cũng có thể được xây dựng với một con trỏ. Thật không may Visual Studio 2013 có vẻ lo lắng về thiết kế của tôi. Trước khi trình bày vấn đề, tôi cần giải thích thiết kế này.Thiết kế mảng động C++

Dưới đây là cách bố trí của lớp học của tôi

template <typename T> 
class Array1D { 
private: 
    T* data_; 
    T* size_; // No stored as an int for optimisation purposes 
    bool owner_; 
public: 
    Array1D(int n) { 
     data_ = new T[n]; 
     size_ = data_ + n; 
     owner_ = true; 
    } 
    Array1D(T* data, int n) { 
     data_ = data; 
     size_ = data + n; 
     owner_ = false; 
    } 
    ... 
}; 

Hầu hết thời gian, nó hoạt động như một std :: vector và owner_ được thiết lập là true. Người ta cũng có thể xây dựng một Array1D từ một con trỏ, và thời gian này owner_ được đặt thành false. Trong trường hợp này, một số thao tác như thay đổi kích thước không được phép (thông qua một khẳng định). Sao chép constructor và phân công cho các mảng A được thiết kế như:

  • Array1D (const Array1D & B): Sâu bản sao của B vào A. Sau khi xây dựng, A sở hữu bộ nhớ của nó.
  • Array1D (Array1D & & B): Di chuyển hoạt động trong mọi trường hợp. Sau khi xây dựng, trạng thái quyền sở hữu của A giống như B.
  • operator = (const Array1D & B): Bản sao B sâu vào A. Nếu A không sở hữu bộ nhớ của nó, xác nhận là có để kiểm tra A và B có cùng kích thước. Bài tập không thay đổi trạng thái quyền sở hữu của A.
  • operator = (Array1D & & B): Di chuyển thao tác nếu A và B sở hữu bộ nhớ của chúng. Nếu không, chúng tôi làm một bản sao sâu, và kích thước được kiểm tra với một khẳng định nếu A không sở hữu bộ nhớ của nó. Việc chuyển nhượng không làm thay đổi tình trạng sở hữu của A.

tôi đã áp dụng ý tưởng tương tự để mảng 2 chiều của tôi mà các thành phần được lưu trữ trong hàng-lớn để

template <typename T> 
class Array2D { 
private: 
    T* data_; 
    T* size_[2]; 
    bool owner_; 
public: 
    Array2D(int n, int p) { 
     data_ = new T[n]; 
     size_[0] = data_ + n; 
     size_[1] = data_ + p; 
     owner_ = true; 
    } 
    Array1D(T* data, int n, int p) { 
     data_ = data; 
     size_[0] = data + n; 
     size_[1] = data + p; 
     owner_ = false; 
    } 
    ... 
    Array1D<T> operator()(int i) { 
     Array1D<T> row(data_ + i * nb_columns(), nb_columns()); 
     return row; 
    } 
    ... 
    int nb_columns() const { 
     return static_cast<int>(size_[1] - data_); 
    } 
}; 

các Array1D trả về bởi toán tử () (int i) không sở hữu bộ nhớ của nó và chứa một con trỏ tới hàng thứ i thuộc sở hữu của đối tượng Array2D. Có ích trong loại mã sau đây

sort(Array1D<T>& A); // A function that sorts array in place 

Array2D<double> matrix(5, 100); // Construct an array of 5 rows and 100 columns 
...        // Fill the array 
sort(matrix(3))     // Sort the 4th row 

"Chế độ xem tạm thời" cho các hàng của mảng 2 chiều khá hữu ích nhưng tôi muốn giới hạn chúng cho các đối tượng tạm thời để hạn chế răng cưa.

Thật không may, sử dụng Visual Studio 2013, tôi nhận được cảnh báo sau từ IDE cho sắp xếp dòng (ma trận (3)): "Tùy chọn cho giá trị r-giá trị ràng buộc với tham chiếu giá trị l là phần mở rộng không chuẩn của Microsoft C++" . Tôi hiểu rằng ma trận (3) là một đối tượng sống tạm thời và sửa đổi nó thông qua một loại có vẻ kỳ lạ. Nhưng, vì nó là một "xem", sửa đổi nó sửa đổi bộ nhớ thuộc sở hữu của ma trận và là hữu ích.

Vì vậy, câu hỏi của tôi như sau:

  • phải là những gì tôi đang làm C++ hợp lệ? (sửa đổi giá trị tạm thời)
  • Có lỗ hổng trong thiết kế này không?

PS: Mã đầy đủ có sẵn trên Github.

+0

Nguyên mẫu của 'loại' bạn đã đưa ra có một loại giá trị, không phải là loại tham chiếu lvalue. – ecatmur

+0

cách toán tử 'Array1D () (int i); 'được triển khai? – Ashalynd

+0

@ecatmut: Cảm ơn nhận xét của bạn. Bài đăng đã được chỉnh sửa. – InsideLoop

Trả lời

0

Tôi đang làm gì hợp lệ C++? (sửa đổi giá trị tạm thời)

Không. tài liệu tham khảo không const vế trái không thể liên kết với đối tượng tạm thời: http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Có một lỗ hổng trong thiết kế này?

Bạn đang sửa đổi nội dung được gói trong một đối tượng. Vì bạn cần phải có một giá trị, nó chỉ đơn giản là sẽ được cố định bằng cách có một biến trung gian:

auto m_temp_lvalue = matrix(3); // get the 4th row 
sort(m_temp_lvalue); // sort the 4th row 

Tôi hy vọng nó sẽ giúp.

+0

Cảm ơn bạn đã giải thích. Mặc dù ý tưởng biến trung gian của bạn hoạt động, cuối cùng tôi đã quyết định tránh những "lượt xem" đó và chỉ có một Array1D trỏ đến một số vị trí trong bộ nhớ. Nó làm cho mọi thứ an toàn hơn. – InsideLoop

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