What is the most efficient way to convert a std::vector to a .NET List?
To give some context, I am wrapping an unmanaged C++ class with C++/CLI. The C++/CLI class holds a pointer to the C++ class and I have a wrapper for each public method.
One method returns a std::vector, so in my wrapper I was going to return the .NET class List. I.e.
// unmanaged class
class A
{
public:
std::vector<int> runList();
}
// managed class
public ref class A
{
public:
// the below is obviously extremely inefficient
List<UInt32> MethodA()
{
std::vector<unsigned int> runList = mpChannelNode->runList();
std::vector<unsigned int>::iterator itr;
List<UInt32> list = gcnew List<UInt32>();
for (itr = runList.begin(); itr != runList.end(); itr++)
{
list.Add(*itr);
}
return list;
}
private:
A* mpChannelNode;
}
How can I make this more efficient? Feel free to recommend a different return type for the .NET class. Lets assume I just need to get that vector into managed world efficiently in any shape or form.
Yes, vector is present in the graph, its line is the same as the x line ! Performing a linear search in a vector is several orders of magnitude faster than in a list. The only reason is the usage of the cache line. When a data is accessed, the data is fetched from the main memory to the cache.
A std::vector can never be faster than an array, as it has (a pointer to the first element of) an array as one of its data members. But the difference in run-time speed is slim and absent in any non-trivial program. One reason for this myth to persist, are examples that compare raw arrays with mis-used std::vectors.
In addition to the requirement that std::array needs to be of compile-time constant length, the reason you would use it over std::vector is performance. std::array requires no dynamic memory allocation, and so can be much cheaper to use than std::vector in the case you know the number of elements.
If you're really that concerned about it, use unverifiable code instead:
List<unsigned>^ MethodA()
{
std::vector<unsigned> const& runList = mpChannelNode->runList();
array<unsigned>^ ret = gcnew array<unsigned>(runList.size());
if (runList.size())
{
pin_ptr<unsigned> dest = &ret[0];
std::memcpy(dest, &runList[0], runList.size() * sizeof(unsigned));
}
return gcnew List<unsigned>(ret);
}
That said, I'd be surprised if there was a noticeable difference either way...
I am not familiar with C++-CLI but one small improvement you can make is to create your list with the right capacity from the beginning.
List<UInt32> list = gcnew List<UInt32>(runList.size());
Another improvement would be to pre-increment your C++ iterator instead of post-incrementing it because currently you create an extra object for every element that is discarded immediately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With