【问题标题】:What is the most efficient way to convert a std::vector<T> to a .NET List<U>?将 std::vector<T> 转换为 .NET List<U> 的最有效方法是什么?
【发布时间】:2011-05-27 00:52:53
【问题描述】:

将 std::vector 转换为 .NET 列表的最有效方法是什么?

为了提供一些上下文,我用 C++/CLI 包装了一个非托管 C++ 类。 C++/CLI 类包含一个指向 C++ 类的指针,并且我为每个公共方法都有一个包装器。

一个方法返回一个 std::vector,所以在我的包装器中我将返回 .NET 类列表。即

// 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;
}

如何提高效率?随意为 .NET 类推荐不同的返回类型。假设我只需要将该向量以任何形状或形式有效地放入托管世界。

【问题讨论】:

  • 如果你只是包装vector&lt;T&gt;,为什么不实现IList&lt;T&gt;并将所有操作代理到vector
  • 嗨,Gabe - 你能把它变成答案吗? :)

标签: .net visual-c++ c++-cli


【解决方案1】:

如果您真的担心它,请改用无法验证的代码:

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);
}

也就是说,如果有明显的差异,我会感到惊讶......

【讨论】:

  • @Seth :正确,它不会,但@Gabe 的建议也不会冒多次编组所有内容的风险(这显然会比你已经拥有的更糟糕)。确实,如果您做出@Marcel 建议的改进,您现在拥有的或多或少是理想的(除非您想要惰性编组)。
  • std::memcpy 与使用 InteropServices 命名空间中的 Marshal.Copy 相比如何? Marshal.Copy 会更安全、更快速吗?
  • @Seth : Marshal::Copy 是根据memcpy 实现的,因此它不会比memcpy 快​​,并且可能会稍微(阅读:可能不明显)慢一些,因为它确实有界-检查。它唯一真正的优势是您的函数不会在 IL 元数据中标记为 unsafe,因为您不需要 pin_ptr,这可能会使从其他 .NET 语言中使用您的类更容易。
【解决方案2】:

我不熟悉 C++-CLI,但您可以做的一个小改进是从一开始就创建具有正确容量的列表。

List<UInt32> list = gcnew List<UInt32>(runList.size());

另一个改进是预先递增 C++ 迭代器而不是后递增它,因为目前您为每个立即丢弃的元素创建一个额外的对象。

【讨论】:

    【解决方案3】:

    考虑将向量直接转换为数组.. 在您调整向量大小之前,以下内容将有效且有效。

    vector<int> vec(10);
    int *array = &vec[0]; 
    

    然后,您应该能够将其(我认为 VS 不在机器上)视为传递的数组来填充您的列表。

    您还应该创建具有您期望需要的大小的列表 - 一个一个添加会很慢。

    【讨论】:

    • 如果是说int* 以某种方式实现了IEnumerable&lt;int&gt;,或者可以传递给List&lt;&gt; 的构造函数,那么不,这是不正确的。
    猜你喜欢
    • 2021-05-29
    • 2019-08-31
    • 2016-03-31
    • 2019-10-20
    • 2013-01-03
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多