我正在学习c ++网站教程,这是对我本学期(初学)大学课程的一个很好的称赞。在学习copy constructors and destructors时,我遇到了这段代码:
// 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别名是否更有效?您仅返回字符串的地址还是字符串本身?刚返回字符串时,又返回整个字符串呢?谢谢。
答案 0 :(得分:0)
返回字符串是不可取的,原因有两个:
const
引用将不允许这样做,并触发编译错误。答案 1 :(得分:0)
字符串成员的吸气剂使我感到困惑。为什么要返回 引用(别名)对象(在这种情况下为字符串)?
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”
一百万个字母
s仍然只有32个字节
由此,您可以得出以下结论:a)“字符串”的实例占用32个字节,而与数据无关。 b)因为所有数据都驻留在其他位置c)因此std :: string实例中的32个字节中的某些字节是指向chars在动态内存中所处位置的指针。
嗯。
如果obj实例只有32个字节,那么您可能会问为什么Example4使用指针将这个SMALL对象(字符串实例)放置到动态内存中……使用8个字节来查找32,然后需要一个第二个引用(位于字符串实例内部的某个指针),以到达Example4字符串的字符。
以相同的方式,std :: vector是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())
<< "\n\n " << "sizeof(*ptr) : " << sizeof(*ptr)
<< " @ 0x" << ptr << ',' // where ptr points to
<< "\n " << "sizeof (ptr) : " << sizeof(ptr)
<< "\n\n";
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() << "'\n\n"
<< 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文件构建的compile命令以
开头g++ -std=c++17 -m64 -ggdb