c++ 取消对可选向量的第一个元素的装箱,然后再次装箱

ct3nt3jp  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(126)

考虑这个例子。

#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
    };
}
  1. makePerson中是否有字符串(等)的副本?
    1.有没有一种方法可以静态地Assert/enfore一个表达式不创建副本?
gjmwrych

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::stringstd::vector的分配器,并观察字符串的内存分配位置或字符串对象的构造位置。你可以禁止向量分配器中的字符串复制构造。
使用标准分配器,您还可以替换全局operator new/operator delete并观察那里的内存分配。但是,如果编译器可以以其他方式提供内存,则允许在某些情况下省略对它们的调用。
如果字符串足够短,可以使用SSO,那么观察内存分配也没有帮助。

相关问题