【问题标题】:A templated 'strdup()'?模板化的“strdup()”?
【发布时间】:2017-02-03 00:58:50
【问题描述】:
template<typename T>
static T *anydup(const T *src, size_t len) {
    T *ptr = malloc(len * sizeof(T));
    memcpy(ptr, src, (len * sizeof(T)));
    return ptr;
}

这样合适吗?使用 int、long 等时,我可以期待任何错误吗?我对泛型编程非常陌生,正在努力学习更多。

【问题讨论】:

  • memcpy 通常不是创建对象的有效方法。所以不,不要这样做。请改用std::vector&lt;T&gt;
  • malloc 也不是实例化对象的有效方法。
  • 复制一些src的正确方法是auto src2{src};
  • 您可以添加static_assert(std::is_trivially_copyable&lt;T&gt;::value, "T must be trivially copyable");
  • 使用矢量,它看起来像std::vector&lt;int&gt; vec = otherVec

标签: c++ templates memcpy strdup


【解决方案1】:

不,这是不对的!当你在 C++ 代码中有一个malloc() 时,你应该变得非常怀疑:

  • malloc() 分配内存,但没有正确创建对象。使用此类内存的唯一方法是使用新放置。
  • memcpy() 不尊重 C++ 对象的复制语义。这只能与可复制的类一起使用。我会在其他地方很难找到错误(浅拷贝和其他导致 UB 的可怕事情)。

对于 char、int、double 等基本类型,它可以工作。但不适用于更复杂的类型。


备选方案 1:调整您的代码以正确创建和复制对象

template<typename T>
T *anydup (const T *src, size_t len) {
    T *ptr = new T[len];                        // requires that T has a default constructor
    copy (src, src+len, ptr);                   // requires that T is copyiable
    return ptr;
}

注意:如果用户忘记删除数组,则存在内存泄漏风险,如果用户不使用delete[],则存在UB!为避免这种情况,您可以选择返回unique_ptr&lt;T[]&gt;


备选方案 2:摆脱数组和指针以及内存噩梦:使用向量!

template<typename T>
vector<T> anydup (const vector<T> src) {
    vector<T> v(len);                        // requires that T has a default constructor
    copy (src.cbegin(), src.cend(), v);      // requires that T is copyable
    return v;
}

您可以考虑使用 Remy Lebeau 和 FDinoff 在 cmets 中建议的复制构造函数创建向量,无论是在函数中还是直接在使用代码中。

如果你在使用代码中直接使用copy(),你很快就会发现还有copy_if()copy_backwards()和其他一些不错的&lt;algorithms&gt;可以根据情况使用。

【讨论】:

  • @PhobosD'thorga 不客气!请参阅我的编辑以获取替代解决方案。我没有测试它,所以它可能有错别字。
  • 在备选方案 2 中。请只使用复制构造函数,不要创建 anydup 方法。
  • @PhobosD'thorga UB 表示未定义的行为(例如,如果您取消引用 NULL 指针可能发生的事情——对不起,nullptr)。 - 是的,C 和 C++ 很接近,但是有一些关键的区别。总之,你需要了解对象模型和rule of 3。如果您将 char* 替换为更强大的 string 并使用向量替换数组,则不再需要许多指针解决方案。
  • 在备选方案 2 中,您可以考虑使用接受迭代器作为输入的向量构造函数:template&lt;typename T&gt; vector&lt;T&gt; anydup (const vector&lt;T&gt; &amp;src) { return vector&lt;T&gt;(src.cbegin(), src.cend()); }
  • 甚至复制构造函数:template&lt;typename T&gt; vector&lt;T&gt; anydup (const vector&lt;T&gt; &amp;src) { return vector&lt;T&gt;(src); }
猜你喜欢
  • 1970-01-01
  • 2022-07-05
  • 2015-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多