避免临时对象失效

https://www.cnblogs.com/wanger-sjtu/p/17202776.html

// DON’T DO THIS
std::string s1, s2;
...
const char* p1 = (s1 + s2).c_str();             // Avoid!
const char* p2 = absl::StrCat(s1, s2).c_str();  // Avoid!

上面的代码在实际过程中需要避免。s1+s2absl::StrCat(s1, s2)的临时对象在执行完当前语句时,就会失效,使得p1 p2成为一个失效的指针。

According to the C++17 standard [class.temporary], “Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created.” (A “full-expression” is “an expression that is not a subexpression of another expression”).

规避措施1:在完整表达式结束之前完成使用临时对象

// Safe (albeit a silly example):
size_t len1 = strlen((s1 + s2).c_str());
size_t len2 = strlen(absl::StrCat(s1, s2).c_str());

规避措施2:存储临时对象。

// Safe (and more efficient than you might think):
std::string tmp_1 = s1 + s2;
std::string tmp_2 = absl::StrCat(s1, s2);
// tmp_1.c_str() and tmp_2.c_str() are safe.

规避措施 3:存储对临时对象的引用。

// Equally safe:
const std::string& tmp_1 = s1 + s2;
const std::string& tmp_2 = absl::StrCat(s1, s2);
// tmp_1.c_str() and tmp_2.c_str() are safe.
// The following behavior is dangerously subtle:
// If the compiler can see you’re storing a reference to a
// temporary object’s internals, it will keep the whole
// temporary object alive.
// struct Person { string name; ... }
// GeneratePerson() returns an object; GeneratePerson().name
// is clearly a sub-object:
const std::string& person_name = GeneratePerson().name; // safe
// If the compiler can’t tell, you’re at risk.
// class DiceSeries_DiceRoll { `const string&` nickname() ... }
// GenerateDiceRoll() returns an object; the compiler can’t tell
// if GenerateDiceRoll().nickname() is a subobject.
// The following may store a dangling reference:
const std::string& nickname = GenerateDiceRoll().nickname(); // BAD!

C++17 standard [class.temporary]: “The temporary to which the reference is bound or the temporary that is the complete object of a sub-object to which the reference is bound persists for the lifetime of the reference.”
c++17标准中要求,临时对象的生命周期与绑定它引用对象的生命周期保持一致。

规避措施 4 设计你的函数,使它们不返回对象

许多函数都遵循这个原则;但也有许多函数不遵循。有时,返回一个对象确实比要求调用者传入一个输出参数的指针要好。要注意何时会发生临时性的创建。c_str()是最明显的罪魁祸首,但protobuf获取器(可变的或其他)和一般的获取器也可能有问题。

虽然函数不返回对象一定程度上可以解决,但在RVO,NRVO优化的场景下,应该没有问题。

posted @ 2023-03-10 11:19  青铜时代的猪  阅读(44)  评论(0)    收藏  举报