在代码中创建了多少临时 std::string 对象? (Effective Modern C++ materials)

问题描述 投票:0回答:0

最近在研究Effective Modern C++11和14

我浏览了本书第 171 页第 25 项的一部分,其中作者为 setName 函数提供了两个代码示例。

(1)

// Option 1, universal reference
class Widget {
public:
    template<typename T>
    void setName(T &&newName)     // universal reference
    { name = std::move(newName); }// compiles, but is // bad, bad, bad!
                                  //…
private:
    std::string name;
    std::shared_ptr<SomeDataStructure> p;
};

void main() {
    Widget w;
    w.setName("Adela Novak");
}

(2)

// Option 2, lvalue reference and rvalue reference
class Widget2 {
public:
    void setName(const std::string &newName) { name = newName; }
    void setName(std::string &&newName) { name = std::move(newName); }
    //…
};

void main() {
    Widget2 w;
    w.setName("Adela Novak");
}

作者说:

随着 setName 的版本采用通用引用,字符串 文字“Adela Novak”将被传递给 setName,它会在哪里 传送给 w 内的 std::string 的赋值运算符。 w的 因此,名称数据成员将直接从字符串中分配 文字;不会出现临时 std::string 对象。

然而,对于 setName 的重载版本,一个临时的 std::string 对象将被创建用于 setName 的参数绑定 到,然后这个临时的 std::string 将被移动到 w 的数据中 成员。因此,对 setName 的调用将需要执行一个 std::string 构造函数(创建临时的),一个 std::string 移动赋值运算符(将 newName 移动到 w.name),以及一个 std::string 析构函数(销毁临时的)。

'''

如果我的理解是正确的,在选项 1 和选项 2 中,我们将在 main() 函数中隐式为“Adela Novak”创建一个临时 std::string 对象。

对于选项 1,我们将临时 std::string 对象发送到 setName(),然后 T&& 将被推断为右值,因为“Adela Novak”是右值。

因此,在选项 1 中,我们只创建一个临时的 std::string 对象。

对于选项 2,我们将临时 std::string 对象发送到 setName()。因为“Adela Novak”是右值,所以我们将选择右值重载 setName() 函数。但是,当我们要调用右值重载函数时,我们必须为 newName 显式创建另一个临时 std::string 对象。

因此,在选项 2 中,我们必须创建两个临时 std::string 对象。

我的问题是:

  1. 为什么我们不必在选项 1 中为 newName 创建另一个临时 std::string 对象?
  2. 为什么我们必须在选项 2 中为 newName 创建另一个临时 std::string 对象?
  3. 如何知道我们要调用的成员函数会不会创建一个临时对象?
c++ c++14 stdstring
© www.soinside.com 2019 - 2024. All rights reserved.