【问题标题】:CComSafeArray to Tab-Separated Values Suggestions for Speed ImprovementCComSafeArray to Tab-Separated Values 提高速度的建议
【发布时间】:2019-08-21 19:35:14
【问题描述】:

我需要将 2D CComSafe 数组转换为制表符分隔值文本流。该数组可以包含任意数量的值,可能以百万计。

相关的代码块如下。

我强烈怀疑 generate_response_from_data 函数只是生成输出的一种残暴方式。但我还没有找到更好方法的具体例子。是的,我已尽我所能进行搜索。

我试图弄清楚 Boost Karma 是否会是一个更好的解决方案,但坦率地说,我只是不知道如何将它应用到我的用例中。

有人可以就更快的方法提供一些意见吗?

// This is a 2D CComSafeArray
template<typename T>
class MyDataArray : public CComSafeArray<T>
{
public:
    MyDataArray() : CComSafeArray<T>() {}

    const T* get_value_ptr(long row, long col) const // 0-based indices.
    {
        // To shave off a tiny bit of time, validity of m_psa, row, and col are assumed.
        // Not great but for our application, those are checked prior to call.
        return &static_cast<T*>(this->m_psa->pvData)[this->m_psa->rgsabound[1].cElements * col + row];
    }

    // Other stuff for this class.
};

inline std::string my_variant_to_string(const VARIANT* p_var)
{
    // Will only ever have VT_I4, VT_R8, VT_BSTR
    if (VT_I4 == p_var->vt)
        return boost::lexical_cast<std::string>(p_var->intVal); // Boost faster than other methods!!!

    if (VT_R8 == p_var->vt)
        return boost::lexical_cast<std::string>(p_var->dblVal); // Boost faster than other methods!!!

    if (VT_BSTR == p_var->vt)
    {
        std::wstring wstr(p_var->bstrVal, SysStringLen(p_var->bstrVal));
        return Utils::from_wide(wstr); // from_wide is a conversion function I created.
    }

    //if (VT_EMPTY == == p_var->vt) {} // Technically not needed.

    return "";
}

template<typename T>
bool generate_response_from_data(const MyDataArray<T>& data_array, std::stringstream& response_body)
{
    if (2 != data_array.GetDimensions())
        return false;

    long row_begin = data_array.GetLowerBound(0);
    long row_end = data_array.GetUpperBound(0);
    long col_begin = data_array.GetLowerBound(1);
    long col_end = data_array.GetUpperBound(1);

    if (row_end < row_begin || col_end < col_begin)
        return false;

    for (long r = row_begin; r <= row_end; ++r)
    {
        for (long c = col_begin; c <= col_end; ++c)
        {
            if (c > 0)
                response_body << '\t';

            response_body << my_variant_to_string(data_array.get_value_ptr(r, c));
        }
        response_body << '\n';
    }

    return true;
}

【问题讨论】:

  • 在 iostreams 中使用细粒度锁定使其成为线程安全的往往是显而易见的。但是“response_body”变量名称强烈暗示您无法在代码中做任何事情来使其更快。通过将 my_variant_to_string() 替换为“testing”来验证这一点。
  • 尝试对结果字符串的大小进行假设,并在填充之前保留空间,
  • 您正在创建大量临时字符串。尝试将my_variant_to_string 更改为&lt;&lt; 运算符重载VARIANT&amp; 实例,并从intVal / dblVal 直接写入流。你可以在你的情况下使用宽字符串吗?如果是这样,您也可以直接从bstrVal 流式传输。
  • 非常感谢大家的建议。我会调查它们(尤其是重载
  • 谢谢@MichaelGunter。您的建议超载

标签: c++ visual-c++ com


【解决方案1】:

感谢@MichaelGunter。您对超载

已编辑以反映使用自定义函数从 BSTR 到 std::string 的直接转换。

std::stringstream& operator<<(std::stringstream& s, const VARIANT* p_v)
{
    if (VT_I4 == p_v->vt)
        s << p_v->intVal;
    else if (VT_R8 == p_v->vt)
        s << p_v->dblVal;
    else if (VT_BSTR == p_v->vt)
    {
        //std::wstring wstr(p_v->bstrVal, SysStringLen(p_v->bstrVal));
        s << Utils::from_bstr(p_v->bstrVal);
    }
    return s;
}

...
response_body << odata_array.get_value_ptr(r, c);

【讨论】:

  • 您还应该有一个Utils::from_wide 重载,它采用BSTR 并产生一个std::string 而没有临时std::wstring。如果您只是使用WideCharToMultiByte,那么超级容易做到。
  • @Michael Guner。感谢您的额外提示。它进一步提高了速度。
  • 我怀疑通过优化 stringstream 并可能按照@xMRi 和其他人的建议进行预分配,我会获得更快的速度。但我不确定优化,也找不到有关预分配空间和/或增加分配空间的信息。
猜你喜欢
  • 2016-09-01
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多