Làm thế nào để xây dựng một chuỗi std :: từ một std :: vector <char>?


115

Thiếu (điều hiển nhiên là) xây dựng chuỗi kiểu C trước rồi sử dụng chuỗi đó để tạo chuỗi std ::, có cách nào nhanh hơn / thay thế / "tốt hơn" để khởi tạo chuỗi từ một vectơ ký tự không?


4
Điều này có thể được thực hiện mà không cần sao chép? Nói cách khác, một cái gì đó làm điều tương tự std::vector<char> v2(std::move(v))nhưng với a std::stringlà đối tượng mới.
tobi_s

Câu trả lời:


197

Cách tốt nhất là sử dụng hàm tạo sau:

template<class InputIterator> string (InputIterator begin, InputIterator end);

điều này sẽ dẫn đến một cái gì đó như:

std::vector<char> v;
std::string str(v.begin(), v.end());

41

Tôi nghĩ bạn chỉ có thể làm

std::string s( MyVector.begin(), MyVector.end() );

trong đó MyVector là vector std :: của bạn.


1
Ngoại trừ trong VS2013 xác nhận trong thời gian chạy về các trình vòng lặp không hợp lệ, trừ khi bạn đặt _ITERATOR_DEBUG_LEVEL=1(trong trường hợp đó, nó có vẻ hoạt động tốt).
Cameron

35

Với C ++ 11, bạn có thể làm std::string(v.data())hoặc, nếu vectơ của bạn không chứa một '\0'ở cuối std::string(v.data(), v.size()),.


Ngay cả với C ++ 98, tôi tin rằng bạn có thể làm std :: string (& v [0]). Tất nhiên, điều này là nếu vector được kết thúc bằng null.
Jamie

1
@Jamie: Nhân tiện, trong C ++ 98, string(&v[0], v.size())cũng sẽ hoạt động, nhưng chỉ sau đó assert(not v.empty());, vì nếu vector trống, cả hai v[0]v.front()sẽ gọi hành vi không xác định. Điều đó, ngoài sự đơn giản về cú pháp của việc không phải sử dụng toán tử address-of, là lợi ích thực sự của hàm của C ++ 11, data()hàm này hoạt động ngay cả trên một vector trống.
Adam H. Peterson

Rất đúng. Thật không may, dự án của tôi bị kẹt trên Visual Studio 2008 trong tương lai gần. Đúng về việc kiểm tra độ dài vectơ trước.
Jamie

Nếu vectơ không chứa '\ 0', std::string(v.data())có thể dẫn đến một chuỗi dài hơn. Vì vậy, không sử dụng cách này.
heLomaN

@heLomaN: Có chuyện gì vậy std::string(v.data(), v.size()), đã được đề cập rõ ràng trong câu trả lời vì lý do chính xác đó?
Sz.

12
std::string s(v.begin(), v.end());

Trong đó v là khá nhiều thứ có thể lặp lại. (Cụ thể là begin () và end () phải trả về InputIterator.)


3

Chỉ để hoàn thiện, một cách khác là std::string(&v[0])(mặc dù bạn cần đảm bảo chuỗi của mình được kết thúc bằng null và std::string(v.data())thường được ưu tiên hơn.

Sự khác biệt là bạn có thể sử dụng kỹ thuật trước đây để truyền vector đến các hàm muốn sửa đổi bộ đệm, điều mà bạn không thể thực hiện với .data ().


Tại sao bạn không thể sử dụng data()để sửa đổi bộ đệm? Tôi trông giống như nếu bạn gọi data()một vectơ không phải const, nó sẽ trả về a T *(và nếu vectơ của bạn là const, 'v [0] `sẽ trả về a T const &).
Adam H. Peterson

@ AdamH.Peterson nó có vẻ là một sự giám sát trong tiêu chuẩn. Dữ liệu của std :: vector có cả hàm const và không const, trong khi trong tiêu chuẩn hiện tại, std :: string chỉ có một hàm const: en.cppreference.com/w/cpp/string/basic_string/data Lưu ý rằng C ++ 17 thêm phiên bản không phải const, vì vậy đây có thể không phải là trường hợp vô thời hạn - tuy nhiên, tiêu chuẩn hiện tại cho biết "Việc sửa đổi mảng ký tự được truy cập thông qua dữ liệu có hành vi không xác định."
Riot

Điều đó sẽ đúng nếu vlà một chuỗi, nhưng kiểu đích là một chuỗi và vlà một vectơ. (Nhưng nó là tốt đẹp để thấy rằng C ++ 17 sẽ cung cấp cho chuỗi chẵn lẻ với vector.)
Adam H. Peterson

@ AdamH.Peterson tất nhiên bạn đúng. Câu hỏi đã được trả lời một lúc trước, tôi đã giả định rằng toàn bộ câu hỏi chỉ là về chuỗi mà không cần kiểm tra.
Riot

2

Tôi thích câu trả lời của Stefan (ngày 11 tháng 9 năm 13) nhưng muốn làm cho nó mạnh mẽ hơn một chút:

Nếu vectơ kết thúc bằng dấu chấm dứt rỗng, bạn không nên sử dụng (v.begin (), v.end ()): bạn nên sử dụng v.data () (hoặc & v [0] cho những người trước C ++ 17) .

Nếu v không có dấu chấm dứt rỗng, bạn nên sử dụng (v.begin (), v.end ()).

Nếu bạn sử dụng begin () và end () và vectơ có số 0 tận cùng, ví dụ: bạn sẽ kết thúc bằng một chuỗi "abc \ 0", có độ dài 4, nhưng thực sự chỉ nên là "abc".


1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());

Bạn có thể thêm một số giải thích cũng như mã?
Paul Floyd

1
Mẫu thư viện chuỗi 11 trong C ++ đi như sau default (1) string (); copy (2) string (const string & str); chuỗi con (3) string (const string & str, size_t pos, size_t len ​​= npos); from c-string (4) string (const char * s); from buffer (5) string (const char * s, size_t n); fill (6) string (size_t n, char c); range (7) template <class InputIterator> string (InputIterator đầu tiên, InputIterator cuối cùng); danh sách khởi tạo (8) string (initializer_list <char> il); move (9) string (string && str) noexcept; chúng tôi đang làm theo mẫu thứ 7.
TechCat

Chào bạn @TechCat! Vui lòng đọc tiếp phần viết câu trả lời hay trước khi trả lời câu hỏi tiếp theo của bạn. Tận hưởng kỳ nghỉ của bạn tại SO!
Khốn nạn.

Bạn có thể chỉnh sửa câu trả lời của mình với phần mô tả được không?
Paul Floyd
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.