当前位置: 首页 > 知识库问答 >
问题:

正在尝试编写字符串类,该类可以从std::string中移动语义

郗浩言
2023-03-14

我正在写我自己的字符串类,真的只是为了学习和巩固一些知识。除了我想有一个使用移动语义学和std::字符串的构造函数之外,我什么都可以做。

在我的构造函数中,我需要复制并清空std::string数据指针和其他东西,它需要保持为空但有效的状态,而不删除字符串所指向的数据,我该怎么做?

目前为止我有这个

class String
{
private:
char* mpData;
unsigned int mLength;
public:
String( std::string&& str)
    :mpData(nullptr), mLength(0)
    {
    // need to copy the memory pointer from std::string to this->mpData

    // need to null out the std::string memory pointer
    //str.clear();  // can't use clear because it deletes the memory
    }
~String()
{
delete[] mpData;
mLength = 0;
}

共有3个答案

岳昊空
2023-03-14

我把这个问题解释为“我能让移动构造函数导致正确的行为”,而不是“我能让移动构造函数最优地快速”。

如果问题是严格的,“有没有一种可移植的方法从std::字符串中窃取内部内存”,那么答案是“没有,因为没有在公共应用编程接口中提供的‘转移内存所有权’操作”。

下面引用移动语义的解释,对“移动构造函数”进行了很好的总结。。。

C 0x引入了一种叫做“右值引用”的新机制,它允许我们通过函数重载来检测右值参数。我们所要做的就是用右值引用参数编写一个构造函数。在这个构造函数中,我们可以对源做任何我们想做的事情,只要我们让它处于有效状态。

基于这种描述,在我看来,您可以实现“移动语义”构造函数(或“移动构造函数”),而无需实际窃取内部数据缓冲区。一个示例实现:

String( std::string&& str)
    :mpData(new char[str.length()]), mLength(str.length())
    {
    for ( int i=0; i<mLength; i++ ) mpData[i] = str[i];
    }

据我所知,移动语义学的意义在于,如果你愿意,你可以更有效率。因为传入的对象是瞬时的,它的内容不需要被保存——所以窃取它们是合法的,但不是强制性的。如果你不转移一些基于堆的对象的所有权,也许实现这一点没有意义,但它似乎应该是合法的。也许它作为垫脚石很有用——你可以窃取尽可能多的有用内容,即使这不是全部内容。

顺便说一句,这里有一个密切相关的问题,即正在构建同一种非标准字符串,并包含std::string的移动构造函数。然而,类的内部是不同的,有人建议std::string可能在内部内置了对移动语义的支持(std::string)-

薛利
2023-03-14

下面的实现实现了所要求的,但有一定的风险。

关于这种方法的注意事项:

>

我取消了delete操作,因为它现在由allocation对象自动执行

如果使用mpData修改底层数据,它将调用所谓的未定义行为。正如这里所指出的,它是未定义的,因为标准说它是未定义的。不过,我想知道,在现实世界中,是否存在const char*std::string::data()的行为与T*std::vector::data()不同的实现——通过这些实现,这样的修改是完全合法的。通过数据()进行的修改可能不会反映在对分配的后续访问中,但基于此问题的讨论,假设没有通过分配对象进行进一步更改,则此类修改似乎不太可能导致不可预测的行为。

它真的为移动语义学优化了吗?这可能是实现定义的。它也可能取决于传入字符串的实际值。正如我在另一个答案中所指出的,移动构造函数提供了一种优化机制——但它并不能保证优化会发生。

class String
{
private:
char* mpData;
unsigned int mLength;
std::string allocation;
public:
String( std::string&& str)
    : mpData(const_cast<char*>(str.data())) // cast used to invoke UB
    , mLength(str.length())
    , allocation(std::move(str)) // this is where the magic happens
    {}
};
蒋胡非
2023-03-14

没有办法做到这一点。std::string的实现由实现定义。每个实现都是不同的。

此外,不能保证字符串将包含在动态分配的数组中。一些std::字符串实现执行小字符串优化,其中小字符串存储在std::字符串对象本身中。

 类似资料:
  • redis 字符串类型

  • 本文向大家介绍详解Swift中的Characters字符类型与String字符串类型,包括了详解Swift中的Characters字符类型与String字符串类型的使用技巧和注意事项,需要的朋友参考一下 一、引言 Swift中提供了String类型与Characters类型来处理字符串和字符数据,Swift中的String类型除了提供了许多方便开发者使用的方法外,还可以与Foundation框架的

  • 在这个问题之前,我先要说明一个事实,那就是我学习编程才一个月,而这个学校的作业却把我难住了。具体地说,它是摩尔斯电码到英语翻译器(反之亦然)...这是我被困住的部分:

  • Rust 中有两种字符串类型:String 和 &str。 String 被存储为一个字节形式(Vec<u3>)的vector ,但确保一定是一个有效的 UTF-8 序列。String 是堆分配的,可增大且无上限。 &str 是一个指向有效 UTF-8 序列的切片(&[u8]),并可在用来查看 String 的内容,就如同 &[T] 是 Vec<T> 的全部或部分引用。(原文:&str is a

  • 问题内容: 我正在尝试从C创建一个go字符串。我有指针和长度,所以如果我从go开始,可以调用该函数。 生成结构,所以我想知道是否可以直接使用它: 我在这里用它来控制我的生命。在随后作为参数传递给函数去: Go的垃圾收集器会尝试回收内存吗? 问题答案: Go的垃圾回收器不会尝试回收使用C内存分配器分配的内存。您所描述的应该是安全的。当然,您可能无法释放C内存,因为您不知道Go将在何时完成。

  • 这种思考方式(静态+动态对于每个字符串是它占用的全部内存)正确吗? 也就是说,如果我有一个Std::string向量,并且我也想计算该向量的所有内存,我需要做同样的事情:我把向量的初始/静态大小加到动态部分,这意味着一个字符串占用的总内存,就像上面对向量中的每个字符串所做的那样? 总而言之,这是我的“缓存”占用的正确内存量吗? 对于每个-我需要添加,另外对于每个-添加??