1. Warum braucht man einen const_string?
Ein const_string ist besonders geeignet für Parser, die nur lesend auf strings operieren. Hierzu ein simples Beispiel:
std::string between_brackets(const std::string& s)
{
std::size_t start = s.find('(');
std::size_t end = s.find(')');
return s.substr(start, end - start);
}
Das Problem dieses Codes ist, dass es den Substring ausschneidet und in einen neuen String kopiert. Der const_string verhindert diesen Overhead.
2. Die Arbeitsweise des const_strings
Der const_string kann Kopien vollständig vermeiden, indem er lediglich einen Zeiger auf den Anfang und auf das Ende des Strings speichert. Er ist nicht Eigentümer der Daten, und kann so mit anderen strings den Inhalt teilen. Wird nun beispielsweise ein Substring erzeugt, wird ein neues const_string Objekt erstellt, bei dem nur begin und end-Zeiger verschoben sind. Der Inhalt selbst wird nicht kopiert.
3. Implementation
Nachdem das Prinzip erklärt wurde, hier nun die Implementierung.
class const_string
{
public:
const_string(const char* str):
begin_(str),
end_(str + std::strlen(str))
{}
const_string(const char* begin, const char* end):
begin_(begin),
end_(end)
{}
const char* begin() const
{
return begin_;
}
const char* end() const
{
return end_;
}
std::size_t size() const
{
return end() - begin();
}
const_string substr(std::size_t pos, std::size_t length = -1)
{
return const_string(begin() + pos, begin() + pos + std::min(size() - pos, n));
}
private:
const char* begin;
const char* end;
};
// Verwendung:
const_string str = "(teststring)";
const_string other_string = str.substr(1, str.size() - 2);
Diese Implementierung dient nur der Verdeutlichung des Prinzips, es fehlen noch einige wichtige Methoden, die ein string haben sollte. Das Interface ist außerdem nicht STL-kompatibel. Eine vollständige(re) Implementierung gibt’s hier.