[英]Why can't we declare a std::vector<AbstractClass>?
[英]Why can't we change data pointer of std::vector?
我有一個數組char* source
和一個向量std::vector<char> target
。 我想讓向量target
指向 O(1) 中的source
,而不復制數據。
這些方面的東西:
#include <vector>
char* source = new char[3] { 1, 2, 3 };
std::vector<char> target;
target.resize(3);
target.setData(source); // <- Doesn't exist
// OR
std::swap(target.data(), source); // <- swap() does not support char*
delete[] source;
為什么不能手動更改向量指向的位置? 如果可能的話,是否會出現一些特定的、無法管理的問題?
C++ vector
class支持添加和刪除元素,保證memory中的連續順序。 如果您可以使用現有的 memory 緩沖區初始化您的vector
,並向其中添加足夠的元素,它會溢出或需要重新分配。
vector
的接口假定它管理其內部緩沖區,也就是說,它可以隨時分配、解除分配、調整大小(當然,在規范范圍內)。 如果您需要一些不允許管理其緩沖區的東西,則不能使用vector
- 使用不同的數據結構或自己編寫一個。
您可以通過復制數據(使用帶有兩個指針或assign
的構造函數)來創建vector
object,但這顯然不是您想要的。
或者,您可以使用string_view
,它看起來幾乎或可能正是您需要的。
std::vector
被認為是底層緩沖區的所有者。 您可以更改緩沖區,但此更改會導致分配,即制作您不想要的源緩沖區的副本(如問題中所述)。
您可以執行以下操作:
#include <vector>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::vector<char> target;
target.resize(3);
target.assign(source, source + 3);
delete[] source;
return 0;
}
將內容替換為 [first, last) 范圍內的內容的副本。
因此再次執行復制。 使用std::vector
時您無法擺脫它。
如果您不想復制數據,那么您應該使用 C++20 中的std::span
(或創建您自己的跨度)或使用std::string_view
(看起來適合您,因為您有一個char
數組)。
第一個選項:使用std::string_view
由於您僅限於 C++17,因此std::string_view
可能非常適合您。 它從source
指向的元素開始構造字符數組的前 3 個字符的視圖。
#include <iostream>
#include <string_view>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::string_view strv( source, 3 );
delete[] source;
return 0;
}
第二個選項:使用 C++20 中的std::span
std::span
來自 C++20,因此它可能不是最適合您的方式,但您可能會對它是什么以及它的工作原理感興趣。 您可以將std::span
視為std::string_view
的一個通用版本,因為它是任何類型的對象的連續序列,而不僅僅是字符。 用法與std::string_view
:
#include <span>
#include <iostream>
int main() {
char* source = new char[3] { 1, 2, 3 };
std::span s( source, 3 );
delete[] source;
return 0;
}
第三個選項:你自己的跨度
如果您僅限於 C++17,您可以考慮創建自己的span
結構。 這可能仍然是一種矯枉過正,但讓我告訴你(順便看看這個更詳細的答案):
template<typename T>
class span {
T* ptr_;
std::size_t len_;
public:
span(T* ptr, std::size_t len) noexcept
: ptr_{ptr}, len_{len}
{}
T& operator[](int i) noexcept {
return *ptr_[i];
}
T const& operator[](int i) const noexcept {
return *ptr_[i];
}
std::size_t size() const noexcept {
return len_;
}
T* begin() noexcept {
return ptr_;
}
T* end() noexcept {
return ptr_ + len_;
}
};
int main() {
char* source = new char[3] { 1, 2, 3 };
span s( source, 3 );
delete[] source;
return 0;
}
所以用法與 C++20 版本的std::span
相同。
std::string_view 和 std::span 是好東西(如果你有支持它們的編譯器版本)。 滾動你自己的類似物也可以。
但是有些人忽略了為什么要對向量執行此操作的全部要點:
Struct[]
+ size_t
並給你所有權std::vector<Struct>
的API所有權可以很容易地轉移到向量中,並且沒有復制!
你可以說:但是自定義分配器,memory 映射文件指針,ROM memory 然后我可以設置為指針呢?
也許會在編譯此代碼時發出警告,但如果可能的話,那就太好了。
我會這樣做:
std::vector
會得到一個構造函數,它要求std::vector::raw_source
std::vector::raw_source
是一個uint8_t*, size_t, bool
結構(目前)bool takeOwnership
: 告訴我們是否取得所有權 (false => copy)size_t size
: 原始數據的大小uint8_t* ptr
:指向原始數據的指針是的 API 我說看起來比單個“set_data(..)”或“own_memory(...)”function 更復雜,但試圖澄清任何曾經使用過這個 Z8A5DA52ED12644427D359E70CA5 的人都非常了解它的含義。 我希望這個 API 存在,但也許我仍然忽略了其他問題原因?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.