当前位置: 首页 > 知识库问答 >
问题:

用const std::vector包装现有内存?

宦文柏
2023-03-14

好的,我最近了解到(a)std::vector根据定义/标准使用连续内存,因此(b)

void printem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) std::cout << iary[i] << std::endl; }
void doublem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) iary[i] *= 2; }

std::vector<int> v;
for (size_t i=0; i<100; ++i) v.push_back(i);
int* iptr = &(v[0]);
doublem(v.size(), iptr);
printem(v.size(), iptr);

好吧,这很酷,但我想换个方向。我有很多现有的代码,比如

double computeSomething(const std::vector<SomeClass>& v) { ... }

如果我有一个对象的C数组,我可以使用这样的代码:

SomeClass cary[100]; // 100*sizeof(SomeClass)
// populate this however
std::vector<SomeClass> v;
for (size_t i=0; i<100; ++i) v.push_back(cary[i]);
// now v is also using 100*sizeof(SomeClass)
double x = computeSomething(v);

我想这样做,(a)没有额外的空间,(b)没有额外的时间将所有数据的冗余副本插入向量。请注意,“只改变你愚蠢的计算方式,白痴”是不够的,因为有数千个这样的函数/方法展示了这种模式,而这些函数/方法不在我的控制之下,即使它们太多了,无法全部改变。

还要注意,因为我只对const std::vector感兴趣

namespace std { template <typename T> class vector {
  vector() { ... }
  vector(size_t n) { ... }
  vector(size_t n, const T& t) { ... }
  const vector(size_t n, T*) { ... } // can this be done?
...

如果这是不可能的,那么从std::vector派生的容器std::const_vector怎么样?它(a)可以从指向c数组和大小的指针构造,并且(b)故意不实现非常量方法(push_back、resize等),因此即使typename为const_vector的对象实际上不是常量对象,只提供const方法的接口实际上是const(任何错误的修改尝试都会在编译时被捕获)?

更新:有点混乱表明,这“解决”了我在Windows上实现std::vector时遇到的问题:

template <typename T>
class vector_tweaker : public std::vector<T> {
public:
  vector_tweaker(size_t n, T* t) {
    _saveMyfirst = _Myfirst;
    _saveMylast  = _Mylast;
    _saveMyend   = _Myend;
    _Myfirst = t;
    _Mylast  = t + n;
    _Myend   = t + n;
  }
  ~vector_tweaker() {
    _Myfirst = _saveMyfirst;
    _Mylast  = _saveMylast;
    _Myend   = _saveMyend; // and proceed to std::vector destructor
  }
private:
  T* _saveMyfirst;
  T* _saveMylast;
  T* _saveMyend;
};

但当然,这个解决方案是可怕的,因为(a)它不能提供保护,防止基类通过调整大小()或push_back()删除原始内存(除了一个谨慎的用户只构造constvector_tweaker()) -- 和(b)它是特定于std::向量的特定实现,并将不得不为其他人重新实现-如果确实其他平台只声明他们的std::向量成员数据是受保护的:就像微软做的那样(似乎是个坏主意)。

共有1个答案

邹锦
2023-03-14

您可以尝试使用std::C11中引入的引用逻辑存储reference_wrapper

SomeClass cary[100];
// ...
std::vector<std::reference_wrapper<SomeClass>> cv;
cv.push_back(cary[i]);   // no object copying is done, reference wrapper is stored

或者不使用C11,您可以为bytes-char创建此类模板类的专门化。然后对于char*C-array中的构造函数,您可以使用::memcpy:不幸的是,这将使用两倍的内存。

::memcpy(&v[0], c_arr, n);

比如:

template <typename T> class MyVector : public std::vector<T> {
};

template <> class MyVector<char> : public std::vector<char> {
    public:
    MyVector<char>(char* carr, size_t n) : std::vector<char>(n) {
        ::memcpy(&operator[](0), carr, n);
    }
};

我建议-尽可能将所有C数组替换为向量,然后不需要额外的复制。

 类似资料:
  • 我以前见过这样做,但我不记得如何有效地初始化已知长度的与长度相同的。这里有一个很好的例子: 我已经仔细阅读了这一页关于高级矩阵初始化的内容,但是没有明确解释执行此操作的方法。

  • 我是否遗漏了包装类中的某些细节? 我有以下程序,在其中我定义了一个类,它包装并提供运算符: 我以为这会编译成同样的东西--它在做同样的计算,所有的东西都是内联的。 编辑-如果我使用而不是,它将产生相同的输出。 编辑-我发布了错误的ASM版本(而不是),因此本节没有帮助。 我在我的Mac电脑上使用Xcode的gcc,在一个64位系统上。除了for-loop的主体之外,结果是相同的。

  • 问题内容: 我知道如何使用rpm列出软件包的内容()。但是,这需要知道.rpm文件在文件系统上的位置。一个更优雅的解决方案是使用包管理器,在我的例子中是YUM。YUM如何用于实现这一目标? 问题答案: 有一个名为YUM 的软件包,它包含一个可以完成此任务的工具。 合并为一个示例: 在至少一个RH v4.8.0,yum v3.2.29和repoquery v0.0.11的RH系统上,什么都不打印。

  • 关于已回答的问题:Java BufferedReader,将InputStream转换为BufferedReader,Java的BufferedReader和InputStreamReader类之间有什么区别? BufferedReader[BR]和InputStreamReader[ISR]都实现了相同的接口。BR拥有ISR拥有的所有方法以及其他方法,包括非常有用的readLine()方法和不那

  • 如果我有一个在类级别上标记为的基本Dao类,这将导致Dao的每个调用都在它自己的事务中运行。 如果我在某个地方创建了一个方法,它使用多个对不同道方法的调用,会怎么样?这些调用中的每一个都将在自己的事务中运行,还是事务将被包装? 如果它被包装,你会认为这是一个很好的做法,在一个通用的DAO类中有<代码> @事务性< /代码>注释,以便DAO可以直接用作<代码> @ AutoWordBaseDaO。

  • 我正在使用画布绘制位图。 考虑这是我的位图(点只是空空间,x标记点): 如果我画这个盒子: 从x开始,我会得到: 但是我想把那些“漏洞百出的”绘制在最左边,就好像这个位图是包装好的一样。就像吃豆人一样。 所以基本上,我想要的是某种方法来指示画布不要在(