3

我目前正在用 C++ 编写自己的字符串实现。(只是为了锻炼)。

但是,我目前有这个复制构造函数:

// "obj" has the same type of *this, it's just another string object
string_base<T>(const string_base<T> &obj)
        : len(obj.length()), cap(obj.capacity()) {
    raw_data = new T[cap];
    for (unsigned i = 0; i < cap; i++)
        raw_data[i] = obj.data()[i];
    raw_data[len] = 0x00;
}

我想提高一点性能。所以我想到了使用memcpy()只是复制obj*this.

就像这样:

// "obj" has the same type of *this, it's just another string object
string_base<T>(const string_base<T> &obj) {
     memcpy(this, &obj, sizeof(string_base<T>));
}

覆盖这样的数据是否安全*this?或者这可能会产生任何问题?

提前致谢!

4

4 回答 4

3

不,这不安全。来自 cppreference.com:

如果对象不是TriviallyCopyable,则 的行为memcpy未指定并且可能未定义。

您的类 is not TriviallyCopyable,因为它的复制构造函数是用户提供的。


此外,您的复制构造函数只会制作浅层副本(如果您愿意,这可能很好,例如,与您的字符串一起应用的写时复制机制)。

于 2018-06-18T10:23:53.147 回答
2

产生问题。所有引用和指针都将被复制,甚至是指向 raw_data 的指针,它与源对象相同。

作为使用 memcpy 的必要条件,您的班级应该:

  • 轻松复制
  • 没有引用或指针,除非:静态指针或不拥有指向的数据。除非您知道自己在做什么,例如实现写入时复制机制,或者何时以其他方式有意和管理此行为。
于 2018-06-18T10:23:08.393 回答
1

正如其他人所说,为了memcpy正常工作,被复制的对象必须是可简单复制的。对于模板中的任意类型T,您无法确定这一点。当然,您可以检查它,但让其他人进行检查要容易得多。与其编写该循环并对其进行调整,不如使用std::copy_n. 它会memcpy在合适的时候使用,在不合适的时候使用逐个元素的复制。所以改变

raw_data = new T[cap];
for (unsigned i = 0; i < cap; i++)
    raw_data[i] = obj.data()[i];

raw_data = new T[cap];
std::copy_n(obj.data(), cap, raw_data);

这也有一点优势,即不在obj.data()每次通过循环时都进行评估,这是您的编译器可能会或可能不会应用的优化。

于 2018-06-18T11:33:23.873 回答
0

从作为成员的有限片段raw_data和指向. 如果你 memcpy 对象,你 memcpy 这个指针。你不复制数组。new[]T

看看你的析构函数。它可能无条件地调用delete[]。它不知道存在多少副本。这意味着它调用delete[]得太频繁了。这是可以修复的:您需要类似于shared_ptr. 这一点都不是微不足道的。您必须担心该共享计数的线程安全性。显然你不能只是memcpy对象,因为那不会更新共享计数。

于 2018-06-18T11:28:35.703 回答