问题
I have an array of data in a C++/CLI array that I can pass to a native function using pin_ptr<T>
, no problem so far. Now, however, I need to pass the array on to a C++/STL function that expects a container such as std::array
or std::vector
.
The easy way of doing this (which I did first), is to copy element by element.
The second-easiest way is to call std::copy()
, see the answer to this question: convert System::array to std::vector.
However, I want to skip the entire copying step and just use the pointer instead. Seeing as std::array
requires a template argument to determine its length, I can't create one at runtime (but please do correct me if I'm wrong). Is there a way to create a vector or a different type of STL container, without unnecessary copying of data?
回答1:
No it's not possible to do without copying, not with the standard containers anyway.
If you're still okay with copying then you should look at the std::vector constructor because I think the easiest way would be to do e.g.
std::vector<T>(your_pointer, your_pointer + number_of_elements)
If you definitely want to avoid copying, then it's not really that hard to write a simple wrapper around the pointer, including simple iterators needed for iteration (the reason it has to be a standard container I guess).
Just for fun and because I had some time over, I created just such a wrapper. It includes indexing and iterators. No bounds-checking.
See https://gist.github.com/pileon/c21cfba496e6c352dd81
Example program using it:
#include <iostream>
#include "pointer_container.h"
int main()
{
int a[20];
std::iota(a, a + 20, 0); // Initialize array
{
std::cout << "From array : ";
for (const auto item : a)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
pointer_container<int> c(a, 20);
{
std::cout << "From container: ";
for (const auto item : c)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
}
Expected output from the program:
From array : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 From container: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
回答2:
Since std::array is just a wrapper you can cast a regular array to a pointer to a std::array. This isn't usable for other containers of course.
#include <array>
#include <iostream>
void test(std::array<int, 10>* pia)
{
std::cout << (*pia)[0] << std::endl;
}
int main()
{
int ix[10]{ 0 };
test((std::array<int, 10> *) ix);
}
回答3:
Since C++20 there is a way to use c++ containers with managed arrays in c++/cli that avoids copying the data: std::span
In c++20 it's possible to use std::span
to wrap a managed c++/cli array. Then it can be used with standard container algorithms.
Unfortunately, Microsoft doesn't support c++/cli beyond c++17. Consequently one must first pass the pointer and length to a function in a different source file that is compiled using c++latest while compiling the caller's source file using the earlier c++17/cli. Fortunately the ABIs are compatible. This is easily set up for each file in the properties page of Visual Studio 2019.
Here's some sample code that creates a small managed array<double>
then calls a function that wraps the managed data with std::span
then sorts with std::sort
// file1.cpp compile with /cli
#include <iostream>
using namespace System;
void sortme(double *p, int len);
int main()
{
array<double>^ v = gcnew array<double> {1.0, 3.0, 2.0, 4.0};
pin_ptr<double> pin=&v[0];
int len=v->Length;
sortme(pin, len);
for (int i = 0; i < len; i++)
std::cout << v[i] << "\n"; // prints sorted array
}
// file2.cpp compile with c++latest
#include <span>
#include <algorithm>
void sortme(double *p, int len)
{
std::span data_clr(p, len);
std::sort(data_clr.begin(), data_clr.end());
}
来源:https://stackoverflow.com/questions/33654056/stdarray-or-stdvector-from-pointer