[英]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.