gpt4 book ai didi

c++ - 关于不可变[string]对象的问题和验证C++

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:42:26 26 4
gpt4 key购买 nike

我一直在对不可变的字符串以及c++的herehere进行一些阅读,而且我认为我对事物的工作方式有很好的了解。但是,我已经建立了一些假设,我想由一些人来进行验证。一些假设比标题所暗示的更为笼统:

  • 虽然C++中的const字符串与STL中的不可变字符串最接近,但它仅是局部不可变的,因此没有体验成为较小对象的好处。因此,它具有标准字符串对象的所有修饰,但无法访问所有成员函数。这意味着它不会在非const之上的程序中创建任何优化吗?而是只是保护对象不被修改?我知道这是一个重要的属性,但我只是想知道使用
  • 的含义
  • 我假设一个对象的成员函数在只读内存中仅存在一次,并且实现可能是特定的,那么const对象在内存中是否有单独的位置?还是成员函数以其他方式受到限制?如果在代码库中仅存在“常量字符串”对象,而没有非常量字符串,则编译器是否会忽略无法访问的函数?
  • 我记得曾经听说过每个字符串文字在c++的只读存储器中仅存储一次,但是在here上我什么都找不到。换句话说,如果我在同一程序中多次使用某些字符串文字,则每个实例都将引用内存中的相同位置。我将假设为否,但是在修改一个字符串对象之前,由相同字符串文字初始化的两个字符串对象会指向同一字符串吗?

  • 如果我在同一篇文章中包含了太多分离的想法,我深表歉意,它们都以字符串表示形式与我有关,只是学习如何更好地编码。

    最佳答案

    据我所知,std::string不能假设输入字符串是数据段中的只读常量字符串。因此,第(3)点不适用。它很可能会分配一个缓冲区并将字符串复制到缓冲区中。

    请注意,C++(与C一样)具有用于编译时的const限定符,出于两个原因使用它是一个好主意:(a)它可以帮助您发现错误,如果声明a = 5;则声明为a,例如const编译失败; (b)编译可能能够更轻松地优化代码(否则可能无法确定对象是常量。)

    但是,C++具有特殊的强制类型转换,以删除变量的const -ness。因此,可以像a一样强制转换const_cast<int&>(a) = 5;变量并为其赋值。 std::string也可以删除其const -ness。 (请注意,C没有特殊的强制类型转换,但是它提供了完全相同的行为:* (int *) &a = 5)

    是否所有类成员都在最终的二进制文件中定义?

    std::string,因为大多数STL使用模板。模板每单位(您的.o目标文件)编译一次,该链接将自动减少重复项。因此,如果您查看所有.o文件的大小并将其相加,则最终输出将非常小。

    这也意味着仅将单元中使用的功能编译并保存在目标文件中。任何其他功能“消失”。话虽这么说,函数A经常调用函数B,所以即使您没有显式调用函数B,也将对其进行定义。

    另一方面,由于这些是模板,因此通常会内联函数。但这是编译器的选择,而不是语言或STL的选择(尽管您可以使用inline关键字来取乐;编译器仍然有权忽略它)。

    较小的对象...不,在C++中,对象的大小非常特定,无法更改。否则,sizeof(something)会随地方而变化,并且C / C++会发疯!

    但是,可以优化保存在只读数据节中的静态字符串。如果链接器/编译器足够好,他们将能够在同一位置合并相同的字符串。当然,这些只是计划char *wchar_t *。微软编译器已经能够做到这一点了。

    但是,字符串上的const并不总是会强制将字符串放入只读数据段中。通常,这取决于您的命令行选项。 C++可能已经纠正了这个问题,但是我认为C除非使用正确的命令行选项,否则仍会将所有内容放在读/写部分中。这是您需要进行测试以确保的结果(您的编译器可能会这样做,但是如果不进行测试,您将不知道。)

    最后,尽管std::string可能不使用它,但C++提供了一个非常有趣的关键字,称为mutable。如果您听说过,您会知道可以将变量成员标记为可变成员,这意味着即使const函数也可以修改该变量成员。使用该关键字的主要原因有两个:(1)您正在编写多线程程序,并且该类必须是多线程安全的,在这种情况下,您将互斥体标记为可变的,非常实用; (2)您想使用一个缓冲区来缓存一个计算成本很高的值,该缓冲区仅在请求该值时才初始化,以免浪费时间,否则该缓冲区也将变为可变的。

    因此,“不变”概念实际上只是您可以在更高层次上依靠的东西。实际上,现实往往大不相同。例如,std::string c_str()函数可以重新分配缓冲区以添加必要的'\ 0'终止符,但是该函数被标记为const:

    const CharT* c_str() const;

    实际上,实现可以自由分配一个完全不同的缓冲区,将其现有数据复制到该缓冲区中并返回该裸指针。这意味着可以在内部为 std::string分配许多缓冲区来存储大字符串(而不是使用可能成本高昂的 realloc())。

    不过,一旦...当您将字符串A复制到字符串B( B = A;)时,就不会复制字符串数据。相反,A和B将共享相同的数据缓冲区。一旦修改了A或B,然后才复制数据。这意味着调用通过复制接受字符串的函数不会浪费那么多时间:
    int func(std::string a)
    {
    ...
    if(some_test)
    {
    // deep copy only happens here
    a += "?";
    }
    }

    std::string b;
    func(b);

    调用func()时不会复制字符串b的字符。如果func()从未修改'a',则字符串数据始终保持不变。通常将其称为浅拷贝或写时副本。

    关于c++ - 关于不可变[string]对象的问题和验证C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26541869/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com