получатель для строкового члена смутил меня. Зачем возвращать
ссылка (псевдоним) на объект (в данном случае строка)?
const string& content() const {return *ptr;}
В чем разница между этим [вернуть ссылку],
и просто вернуть строку?
string content() const { return *ptr;}
И вы можете спросить, есть ли разница между этим
и возвращает только указатель
const string* content() const { return ptr;}
- Я не нахожу преимущества одного над другим.
Что ж, возможно, рассмотрим сценарий, в котором строка содержит 26 миллионов символов, возможно, вы захотите избежать копирования.
Но есть еще одна проблема (или, может быть, 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"
Исходя из этого, вы можете сделать вывод, что a) экземпляр 'string' занимает 32 байта независимо от данных. б) потому что все данные находятся в другом месте; в) поэтому некоторые из 32 байтов в экземпляре std :: string являются указателями на то, где в динамической памяти находятся символы.
Хм.
Если экземпляр obj составляет всего 32 байта, то вы можете спросить, почему Example4 использует указатель для помещения этого МАЛЫХ объектов (экземпляра строки) в динамическую память ... используя 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-файлом, начинается с:
g++ -std=c++17 -m64 -ggdb