我听取了香草萨特最近的谈话谁建议的理由来传递std::vector和std::string利用const &在很大程度上消失了.他建议现在更好地编写如下函数:
std::string do_something ( std::string inval )
{
std::string return_val;
// ... do stuff ...
return return_val;
}
Run Code Online (Sandbox Code Playgroud)
我理解return_val在函数返回时将是一个rvalue,因此可以使用非常便宜的移动语义返回.但是,inval仍然远大于引用的大小(通常实现为指针).这是因为a std::string具有各种组件,包括指向堆的指针和char[]用于短字符串优化的成员.所以在我看来,通过引用传递仍然是一个好主意.
谁能解释为什么Herb可能会说这个?
这个答案给出了短字符串优化(SSO)的一个很好的高级概述.但是,我想更详细地了解它在实践中是如何工作的,特别是在libc ++实现中:
为了符合SSO资格,字符串有多短?这取决于目标架构吗?
在访问字符串数据时,实现如何区分短字符串和长字符串?它m_size <= 16是一个简单的,还是一个标志,是其他成员变量的一部分?(我想这m_size或其中的一部分也可能用于存储字符串数据).
我专门针对libc ++问了这个问题,因为我知道它使用SSO,甚至在libc ++主页上也提到过.
以下是查看来源后的一些观察结果:
libc ++可以使用两个稍微不同的字符串类内存布局进行编译,这由_LIBCPP_ALTERNATE_STRING_LAYOUT标志控制.这两种布局还区分了little-endian和big-endian机器,这使我们总共有4种不同的变体.我将在下面的内容中假设"正常"布局和小端.
假设进一步size_type是4个字节并且value_type是1个字节,这就是字符串的前4个字节在内存中的样子:
// short string: (s)ize and 3 bytes of char (d)ata
sssssss0;dddddddd;dddddddd;dddddddd
^- is_long = 0
// long string: (c)apacity
ccccccc1;cccccccc;cccccccc;cccccccc
^- is_long = 1
Run Code Online (Sandbox Code Playgroud)
由于短字符串的大小在高7位,因此在访问它时需要移位:
size_type __get_short_size() const {
return __r_.first().__s.__size_ >> 1;
}
Run Code Online (Sandbox Code Playgroud)
类似地,长字符串容量的getter和setter用于__long_mask解决这个问题is_long.
我仍在寻找我的第一个问题的答案,即__min_cap短字符串的容量对不同的架构有什么价值?
其他标准库实现
这个答案很好地概述了std::string其他标准库实现中的内存布局.
我很好奇为什么下面的代码:
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNO";
}
Run Code Online (Sandbox Code Playgroud)
当使用编译时,将-O3产生以下代码:
main: # @main
xor eax, eax
ret
Run Code Online (Sandbox Code Playgroud)
(我完全理解不需要多余的,a因此编译器可以从生成的代码中完全忽略它)
但是以下程序:
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNOP"; // <-- !!! One Extra P
}
Run Code Online (Sandbox Code Playgroud)
产量:
main: # @main
push rbx
sub rsp, 48
lea rbx, [rsp + 32]
mov qword ptr [rsp + 16], rbx
mov qword ptr [rsp + 8], 16
lea rdi, [rsp + 16]
lea rsi, [rsp + 8]
xor …Run Code Online (Sandbox Code Playgroud) 我最近看到我的一位同事std::string用作缓冲区:
std::string receive_data(const Receiver& receiver) {
std::string buff;
int size = receiver.size();
if (size > 0) {
buff.resize(size);
const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);
}
return buff;
}
Run Code Online (Sandbox Code Playgroud)
我猜这家伙想利用返回字符串的自动销毁功能,因此他不必担心释放分配的缓冲区。
这对我来说有点奇怪,因为根据cplusplus.com,该data()方法返回const char*指向由字符串内部管理的缓冲区的指针:
const char* data() const noexcept;
Run Code Online (Sandbox Code Playgroud)
Memcpying到一个const char指针?AFAIK只要知道我们所做的事情就不会造成伤害,但是我错过了什么吗?这很危险吗?
我很想知道如何实现std :: string以及它与c字符串的区别?如果标准没有指定任何实现,那么任何带有解释的实现都会很好,它如何满足标准给出的字符串要求?
我的代码经常将C++字符串转换为CStrings,我想知道原始字符串是否在堆栈上分配,CString也会在堆栈上分配吗?例如:
string s = "Hello world";
char* s2 = s.c_str();
Run Code Online (Sandbox Code Playgroud)
会s2在堆栈上还是在堆中分配?换句话说,我需要删除s2吗?
相反,如果我有这个代码:
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
Run Code Online (Sandbox Code Playgroud)
请问s2现在在堆中,因为它的起源是在堆上?
为了澄清,当我询问是否s2在堆上时,我知道指针在堆栈上.我问的是它指向堆或堆栈的内容.
我知道我不应该优化我的程序的每一个位置所以请认为这个问题是"学术的"
我有每个最多100个字符串和整数,类似的东西:
MSFT 1
DELL 2
HP 4
....
ABC 58
Run Code Online (Sandbox Code Playgroud)
这个集合是预先初始化的,这意味着一旦创建它就永远不会改变.初始化set后我使用它非常密集,所以很快就能快速查找.字符串很短,最多30个字符.映射int也是有限的,介于1和100之间.
至少知道字符串是预先初始化的并且永远不会改变它应该可以"找到"导致"一篮子一项"映射的哈希函数,但可能还有其他黑客.
我能想象的一个优化 - 我只能读取第一个符号.例如,如果"DELL"是唯一以"D"开头的字符串,并且我收到了类似"D***"的内容,而不是我甚至不需要阅读字符串!它显而易见地"戴尔".这种查找必须比"hashmap lookup"快得多.(在这里,我假设我们只接收哈希中的符号,但并非总是如此)
我的问题是否有任何可以使用或易于实施的解决方案?我正在使用c ++和boost.
upd我检查并发现,对于我的交易限制,股票代码是12个符号,而不是如上所述的30个符号.然而,其他交换可能允许稍微长一些的符号,因此有一个算法可以继续处理多达20个字符长的代码,这很有意思.
有几个构造的std::string.我正在寻找一种避免重新分配的方法,我很惊讶有一个填充构造函数,但没有"保留"构造函数.
std::string (size_t n, char c);
Run Code Online (Sandbox Code Playgroud)
但不是
std::string (size_t n);
Run Code Online (Sandbox Code Playgroud)
所以我必须reserve()在它已经分配了默认值(在我的情况下是16个字节)之后调用,只是为了立即重新分配它?
有没有这样的构造函数在创建对象时直接保留空间的原因,而不是必须手动执行?或者我错过了什么,有一些方法可以做到这一点?
使用fill构造函数是浪费时间,因为它将遍历内存只是为了被覆盖,并且还会导致错误的大小,因为s.length()报告N而不是0.
我读了一些GCC bugreport,那里有人在谈论"vstring".搜索WEB我注意到http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.2/vstring_8h.html.
有人可以详细说明它有用和用于什么?为什么用它代替std :: string?