考虑这个例子。
#include <optional>
#include <string>
#include <vector>
struct Person {
std::optional<std::string> name;
};
std::optional<std::vector<std::string>> makeNames() {
return {{"adam", "eve"}};
}
Person makePerson() {
auto names = makeNames();
return {
names ? std::make_optional(std::move((*names)[0])) : std::nullopt
};
}
makePerson
中是否有字符串(等)的副本?
1.有没有一种方法可以静态地Assert/enfore一个表达式不创建副本?
1条答案
按热度按时间gjmwrych1#
在makePerson中是否有字符串(等)的副本?
不,
std::string
s不会被复制。但是std::vector
s和std::string
s被移动。std::string
仅在std::make_optional
中移动,以嵌入到函数返回的可选值中。这是不可能避免的,因为std::optional
将它所保存的值嵌入到了自身中。如果不需要,可以使用std::unique_ptr
。std::string
s仅在std::vector
被复制时才被复制,而在std::vector
被移动时不会被复制。std::vector
的move构造函数也不会移动字符串元素。然而,在
makeNames
中有字符串复制构造,因为使用了不支持移动语义的std::initializer_list
构造函数。如果你在一个合适的reserve
之后使用emplace_back
,那么你可以用makeNames
中字符串的所有副本/移动来交换一个可能被省略的vector move构造。如果使用不同的元素类型而不是
std::string
,则上述内容不会发生变化。有没有一种方法可以静态地Assert/enfore一个表达式不创建副本?
不可以,但是你可以将
std::string
Package 在一个不可复制的类中,然后看看当使用 Package 的字符串作为元素类型时编译是否会失败。类似地,您可以 Package
std::vector
,使其不可复制,从而无法复制字符串。您还可以替换
std::string
或std::vector
的分配器,并观察字符串的内存分配位置或字符串对象的构造位置。你可以禁止向量分配器中的字符串复制构造。使用标准分配器,您还可以替换全局
operator new
/operator delete
并观察那里的内存分配。但是,如果编译器可以以其他方式提供内存,则允许在某些情况下省略对它们的调用。如果字符串足够短,可以使用SSO,那么观察内存分配也没有帮助。