Thay thế cho vectơ <bool>


90

Như (hy vọng) chúng ta đều biết, vector<bool>nó hoàn toàn bị hỏng và không thể được coi là một mảng C. Cách tốt nhất để có được chức năng này là gì? Cho đến nay, những ý tưởng tôi đã nghĩ ra là:

  • Sử dụng một vector<char>thay thế, hoặc
  • Sử dụng một lớp trình bao bọc và có vector<bool_wrapper>

Làm thế nào để các bạn xử lý vấn đề này? Tôi cần c_array()chức năng.

Một câu hỏi phụ, nếu tôi không cần c_array()phương pháp, cách tốt nhất để tiếp cận vấn đề này nếu tôi cần truy cập ngẫu nhiên là gì? Tôi có nên sử dụng deque hay thứ gì khác không?

Biên tập:

  • Tôi cần định cỡ động.
  • Đối với những người chưa biết, vector<bool>là chuyên ngành để mỗi người boolmất 1 chút. Vì vậy, bạn không thể chuyển đổi nó thành một mảng kiểu C.
  • Tôi đoán "wrapper" là một từ nhầm lẫn một chút. Tôi đã nghĩ một cái gì đó như thế này:

Tất nhiên, sau đó tôi phải đọc my_booldo các vấn đề về căn chỉnh có thể xảy ra :(

struct my_bool
{
    bool the_bool;
};
vector<my_bool> haha_i_tricked_you;

2
Có một số lý do để không sử dụng ... một mảng kiểu C?
kquinn

rlbond, bạn có cần kích thước động không?
Johannes Schaub - litb

16
Ok, tôi sẽ cắn - tại sao bạn nghĩ vector là "" hoàn toàn bị phá vỡ"?
Andrew Grant


4
Điều thú vị vector<bool>là vừa gây ra lỗi chạy đua dữ liệu trong mã của tôi, vì tôi mong đợi các luồng khác nhau có thể sửa đổi các phần tử khác nhau trong vector cùng một lúc một cách an toàn. Đã giải quyết bằng cách sử dụng deque<bool>.
Andres Riofrio

Câu trả lời:



21

Đó là một vấn đề thú vị.

Nếu bạn cần một std :: vector nếu nó không chuyên biệt, thì có thể một cái gì đó tương tự sẽ hoạt động tốt với trường hợp của bạn:

#include <vector>
#include <iostream> 
#include <algorithm>

class Bool
{
public:

    Bool(): m_value(){}
    Bool( bool value ) : m_value(value){}

    operator bool() const { return m_value; }

    // the following operators are to allow bool* b = &v[0]; (v is a vector here).
    bool* operator& () { return &m_value; }
    const bool* operator& () const { return &m_value; }

private:

    bool m_value;

};




int main()
{
    std::vector<Bool> working_solution(10, false);


    working_solution[5] = true;
    working_solution[7] = true;


    for( int i = 0; i < working_solution.size(); ++i )
    {
        std::cout<< "Id " << i << " = " << working_solution[i] << "(" <<(working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::sort( working_solution.begin(), working_solution.end());
    std::cout<< "--- SORTED! ---" << std::endl;

    for( int i = 0; i < working_solution.size(); ++i )
    {
            bool* b = &working_solution[i]; // this works!

        std::cout<< "Id " << i << " = " << working_solution[i] << "(" << (working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::cin.get();
    return 0;
}

Tôi đã thử điều này với VC9 và nó có vẻ hoạt động tốt. Ý tưởng của lớp Bool là mô phỏng kiểu bool bằng cách cung cấp cùng một hành vi và kích thước (nhưng không cùng kiểu). Hầu như tất cả công việc được thực hiện bởi toán tử bool và các hàm tạo sao chép mặc định ở đây. Tôi đã thêm một loại để chắc chắn rằng nó phản ứng như giả định khi sử dụng các thuật toán.

Không chắc nó sẽ phù hợp với mọi trường hợp. Nếu nó phù hợp với nhu cầu của bạn, sẽ ít công việc hơn là viết lại một lớp dạng vector ...


"chúng tôi có thể thêm toán tử bool * & () {return & m_value;}" - err. ISO : " sizeof(bool)không cần phải được 1"
Evgeny Panasyuk

2
Tôi muốn chỉ cần thay đổi operator bool() constthành một operator bool&(). Điều này làm cho nó phản ánh hành vi của bool đơn giản tốt hơn vì nó hỗ trợ chuyển nhượng, v.v. trong những trường hợp chẳng hạn như v[0] = true;tôi thực sự không thể thấy vấn đề với thay đổi này, vì vậy tôi có thể thực hiện chỉnh sửa không?
Agentlien

19

Tùy thuộc vào nhu cầu của bạn. Tôi sẽ đi cho một trong hai std::vector<unsigned char>. Viết một trình bao bọc có thể tốt nếu bạn chỉ sử dụng một tập hợp con của chức năng, nếu không nó sẽ trở thành một cơn ác mộng.


unsigned charluôn là một byte đơn trong khi uint8_tcó thể không được hỗ trợ bởi việc triển khai. uint_fast8_tcó thể làm việc mặc dù nếu mục đích là làm cho nó rõ ràng đó là một byte đơn và không phải là một nhân vật, nhưng bạn cũng có thể sử dụng std::bytesau đó
Gabriel Ravier

13

Làm thế nào để các bạn xử lý vấn đề này? Tôi cần chức năng c_array ().

boost::container::vector<bool>:

Chuyên môn hóa vectơ < bool > gặp khá nhiều vấn đề và đã có một số lần thử không thành công để phản đối hoặc xóa nó khỏi tiêu chuẩn. Boost.Containerkhông triển khai nó vì có một Boost cao cấp hơn.DynamicBitset giải pháp .

...

Vì vậy, boost :: container :: vector :: iterator trả về các tham chiếu bool thực và hoạt động như một vùng chứa hoàn toàn tuân thủ. Nếu bạn cần phiên bản tối ưu hóa bộ nhớ của các chức năng boost :: container :: vector < bool >, hãy sử dụng Boost.DynamicBitset .


6

Hãy xem xét sử dụng một vectơ <int>. Khi bạn vượt qua quá trình biên dịch và kiểm tra kiểu, bool và int đều chỉ là các từ máy (chỉnh sửa: rõ ràng điều này không phải lúc nào cũng đúng; nhưng sẽ đúng trên nhiều kiến ​​trúc PC). Trong những trường hợp bạn muốn chuyển đổi mà không có cảnh báo, hãy sử dụng "bool foo = !! bar", chuyển đổi 0 thành false và khác 0 thành true.

Một vectơ <char> hoặc tương tự sẽ sử dụng ít dung lượng hơn, mặc dù nó cũng có khả năng đạt tốc độ (rất nhỏ) trong một số trường hợp, vì các ký tự nhỏ hơn kích thước từ máy. Tôi tin rằng đây là lý do chính mà các bools được triển khai bằng cách sử dụng int thay vì ký tự.

Nếu bạn thực sự muốn có ngữ nghĩa rõ ràng, tôi cũng thích đề xuất tạo lớp boolean của riêng bạn - trông giống như bool, hoạt động giống bool, nhưng đánh lừa sự chuyên môn hóa của khuôn mẫu.

Ngoài ra, chào mừng bạn đến với câu lạc bộ những người muốn chuyên ngành vectơ <bool> bị loại bỏ khỏi tiêu chuẩn C ++ (với bit_vector để thay thế nó). Đó là nơi tất cả những đứa trẻ tuyệt vời đi chơi :).


4

Vấn đề này đã được thảo luận trên comp.lang.c ++. Đã được kiểm duyệt. Đề xuất giải pháp:

  • trình cấp phát của riêng bạn (dựa trên std::allocator) và chuyên môn hóa vectơ của riêng bạn;
  • sử dụng std::deque(ngay từ đầu đã được đề xuất trong một trong những cuốn sách của S. Mayers) - nhưng điều này không phù hợp với yêu cầu của bạn;
  • tạo booltrình bao bọc POD ;
  • sử dụng một cái gì đó ( char/ int/ etc) với cùng kích thước boolthay thế bool;

Cũng sớm, tôi đã thấy đề xuất cho ủy ban tiêu chuẩn - giới thiệu vĩ mô (đại loại như STD_VECTOR_BOOL_SPECIAL ) để không cho phép chuyên môn này - nhưng AFAIK đề xuất này không được thực hiện trong các triển khai stl và không được chấp thuận.

Có vẻ như vấn đề của bạn không có cách nào để làm điều này độc đáo ... Có thể trong C ++ 0x.


3

Câu trả lời đơn giản nhất là sử dụng vector<struct sb>nơi sbstruct {boolean b};. Sau đó, bạn có thể nói push_back({true}). Nó có vẻ tốt.


2

Cách giải quyết ưa thích của tôi là một vectorenum theo phạm vi có một loại cơ bản là bool. Điều này khá gần với những gì vector<bool>chúng ta đã có nếu ủy ban không chuyên trách nó.

enum class switch_status : bool { ON, OFF };

static_assert( sizeof( switch_status ) == 1 );

::std::vector<switch_status> switches( 20, switch_status::ON );

static_assert( ::std::is_same_v< decltype( switches.front() ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches.back()  ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches[ 0 ]    ), switch_status &> );

Bạn sẽ có ý kiến ​​của riêng mình về sự khôn ngoan của việc nắm bắt các phôi đến / đi bool:

enum class switch_status : bool { OFF = false, ON = true };

static_assert( static_cast< bool          >( switch_status::ON  ) == true               );
static_assert( static_cast< bool          >( switch_status::OFF ) == false              );
static_assert( static_cast< switch_status >( true               ) == switch_status::ON  );
static_assert( static_cast< switch_status >( false              ) == switch_status::OFF );
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.