根据 C++ 标准,这种对临时访问是否安全?

Is this access to temporary safe according to the C++ standard?

提问人:jan.sende 提问时间:11/9/2023 最后编辑:jan.sende 更新时间:11/10/2023 访问量:117

问:

我最近在 C++ 代码库中发现了以下 Code Pattern,我现在想知道根据 C++ 标准它是否安全。(实际代码将指针传递到多个函数层,但我将其压缩为基本形式。const char*

#include <string>

class NetworkSocket
{
public:
    void SetPort(const char* port)
    {
        m_port = port;
    }

private:
    std::string m_port;
};

int main()
{
    const int     port   = 42;
    NetworkSocket socket = {};

    socket.SetPort(std::to_string(port).c_str());
}

具体来说,我想知道调用是否安全,或者我们是否正在调用未定义的行为,或者访问(可能)已删除的内存。SetPort()

我试图使用 cppreference 自己弄清楚,但被困在定义中。我得到了:

  1. std::to_string()返回一个 PRE值,从而创建一个临时对象。
  2. 调用延长临时的生存期。(至少从 C++17 开始,在我不确定之前。c_str())
  3. 从现在开始,我不确定。临时的生存期似乎到此结束,使得对指针的访问成为未定义的行为。但是,当我尝试通过 clang 的未定义行为清理器运行代码时,没有发现任何问题......https://godbolt.org/z/EfcvePoWeconst char*

请引用相关标准规则,并说明标准版本之间的差异(如果有的话)。

C++ 语言律师 生存期 临时对象

评论

2赞 273K 11/9/2023
这是安全的。你不保留它,你复制它。有一堆这样的答案。
3赞 273K 11/9/2023
c_str()不会延长寿命,临时字符串在;
1赞 Weijun Zhou 11/9/2023
相反,如果它的其余部分没有改变,那将是不安全的。private: const char* m_port
1赞 NathanOliver 11/9/2023
std::to_string(port).c_str()活到尽头,所以你是安全的socket.SetPort(std::to_string(port).c_str());
4赞 Weijun Zhou 11/9/2023
不,除了少数例外,临时存在到包含它的完整表达式的末尾。在本例中,完整表达式为socket.SetPort(std::to_string(port).c_str())

答:

4赞 Sam Varshavchik 11/9/2023 #1

这是明确定义的。

12.2 临时对象 [class.temporary]

... 临时对象被销毁,作为评估完整对象的最后一步。 表达式 ([intro.execution]) (词法上)包含 他们被创造出来了。

1.9 程序执行 [intro.execution]

... 完整表达式是不是另一个表达式的子表达式的表达式。

这里:

socket.SetPort(std::to_string(port).c_str());

临时对象是作为 的返回值的对象。不出所料,完整的表达就是整个表达。因此,临时对象 - 拥有它的对象 - 在调用返回后被销毁。结束。std::stringstd::to_stringc_str()SetPort()

(此规则有两个例外,它们在这里不适用)。