返回常量对象引用 (getter) 和仅返回字符串有什么区别?

What's the difference between returning a const object reference (getter), and just the string?

本文关键字:返回 字符串 什么 区别 常量 对象引用 getter      更新时间:2023-10-16

我正在浏览c++网站教程,这是对我这学期(初学者(正在学习的大学课程的一种很好的赞扬。在学习复制构造函数和析构函数时,我遇到了以下代码段:

// destructors
#include <iostream>
#include <string>
using namespace std;
class Example4 {
string* ptr;
public:
// constructors:
Example4() : ptr(new string) {}
Example4 (const string& str) : ptr(new string(str)) {}
// destructor:
~Example4 () {delete ptr;}
// access content:
const string& content() const {return *ptr;}
};
int main () {
Example4 foo;
Example4 bar ("Example");
cout << "bar's content: " << bar.content() << 'n';
return 0;
}

现在,我理解了析构函数部分,但字符串成员的getter让我感到困惑。为什么要返回对对象(本例中为字符串(的引用(别名(?

// access content:
const string& content() const {return *ptr;}

这和只返回字符串有什么区别?

string content() const {
return *ptr;
}

返回常量别名是否更有效?您返回的只是字符串的地址,还是字符串本身?如果只是返回字符串,你会返回整个字符串吗?谢谢

返回字符串是不可取的,原因有两个:

  • 这意味着执行了不必要的字符串副本,这对性能不利
  • 这也意味着,有人可能会试图修改返回的字符串,认为他们修改了类的实际成员——const引用不允许这样做,并触发编译错误
字符串成员的getter让我感到困惑对象的引用(别名((本例中为字符串(?
const string& content() const {return *ptr;}

[返回引用]与,只是把绳子还回来?

string content() const { return *ptr;}

您可能会问这两者之间是否有区别并且只返回指针

const string* content() const { return ptr;} 

  • 我没有发现一个比另一个有优势

好吧,也许考虑一下字符串包含2600万个字符的场景,你可能想避免复制它。

但是,如果只是为了评估你在这里学到的东西,你还应该意识到另一个问题(或者可能是2个(。


在Lubuntu 18.04上,使用g++(Ubuntu 7.3.0-27(,一个字符串s,没有数据,

std::string s; 
cout << sizeof(s) << "  " << s.size() << endl;

报告数字"32 0"。


std::string s ("01234567890123456789"); 
cout << sizeof(s) << "  " << s.size() << endl;

报告值"32 20">


{
std::string s;
for (int i=0; i<1000000; i++)
{
for (char j='A'; j<='Z'; j++)
s.push_back(j);
}
cout << "  " << sizeof(s) << "  " << s.size() << endl;
}

报告值"32 26000000">

  • 100万个字母

  • s仍然只有32字节

由此,您可以得出a("string"的实例占用32个字节,而与数据无关。b( 因为所有数据都位于其他地方c(,所以std::string实例中的32个字节中的一些字节是指向动态内存中字符所在位置的指针。


嗯。

如果obj实例只有32个字节,那么您可能会问Example4为什么使用指针将这个SMALL对象(字符串实例(放入动态内存中。。。使用8个字节找到32,然后需要第二个引用(字符串实例内部的某个指针(来到达Example4字符串的char。

同样,std::向量是24个字节(不管元素有多少,也不管元素有多大(。std::vector负责内存管理,这样你就不必这么做了。

也许这节课是为了帮助你发现和评估动态记忆中的内容,以及自动记忆中的信息,以改进你的选择。

关键思想是STL库容器为您处理动态内存,从而大大简化您的工作。


或者,也许教授想让你更多地了解你正在使用的工具。在某些方面,标准容器将您与这些东西的工作方式隔离开来。也许这项任务是为了了解std::string的作用。


//这里有一些"g++-std=c++17"代码,可以一步到位,说明的几个想法

#include <iostream>
using std::cout, std::endl;
#include <sstream>
using std::stringstream;
#include <iomanip>
using std::setfill, std::setw;
#include <string>
using std::string;
#include <cstring>
using std::strlen;

class Example4
{
string* ptr;
public:
Example4() : ptr(new string) {}
Example4 (const string& str) : ptr(new string(str)) {}
~Example4 () {delete ptr;}
// access content:
const string& content() const {return *ptr;}
const string* contentP() const {return  ptr;}
string show(string lbl)
{
stringstream ss;
ss << "n  " << lbl
<<             "               .  5         4         3         2         1"
<< "n                         . '09876543210987654321098765432109876543210987654321'"
<< "n  " << "*ptr                   : '" << *ptr  << "'"
<< "n  " << "(*ptr).size()          : " << (*ptr).size()
<< "n  " << "  ptr->size()          : " <<   ptr->size()
<< "n  " << "strlen((*ptr).c_str()) : " << strlen((*ptr).c_str())
<< "n  " << "strlen(ptr->c_str())   : " << strlen(ptr->c_str())
<< "nn  " << "sizeof(*ptr)           : " << sizeof(*ptr)
<< "     @ 0x" << ptr << ',' // where ptr points to
<< "n  " << "sizeof (ptr)           : " << sizeof(ptr)
<< "nn";
return ss.str();
}
};

class T996_t
{
public:
int operator()() { return exec(); }
private: // methods
int exec()
{
Example4 e4("Now is the time to answer all questions01234567890");
cout << "n  "  <<  e4.show("Example4")
<< "n  '" <<  e4.content() << "'"
<< "n  '" << *e4.contentP() << "'nn"
<< endl;
{
std::string s;
cout << "  " << sizeof(s) << "  " << s.size() << endl;
}
{
std::string s("01234567890123456789");
cout << "  " << sizeof(s) << "  " << s.size() << endl;
}
{
std::string s;
for (int i=0; i<1000000; i++)
{
for (char j='A'; j<='Z'; j++)
s.push_back(j);
}
cout << "  " << sizeof(s) << "  " << s.size() << endl;
}
return 0;
}
}; // class T996_t
int main(int, char**) { return T996_t()(); }

这段代码在我的Lubuntu上编译并运行。我的make文件构建的编译命令以开头

g++ -std=c++17 -m64 -ggdb