Code Bye

关于 RVO 的一点疑问,求高手指点

#include <cstdlib>
#include <string>
using namespace std;
struct Useful {
    Useful(char* buff) : _buff(buff) {}
    ~Useful() {
        if (_buff) {
            std::free(_buff);
        }
    }
    char* _buff;
};
string testRVO() {
    const char* raw = "blacksheep wall,show me the money";
    // 有分配内存的操作
    char* buff = reinterpret_cast<char*>(std::malloc(1024));
    strcpy(buff, raw);
    // 离开方法是自动将 buff 释放掉(应该是 return 先于 free 吧?不太确定)
    Useful use(buff);
    return string(buff, strlen(buff));
}

Useful 到底是 Useless 还是 Useful?

解决方案:20分
根据先定义,后释放销毁原则,应该是 use后销毁
但是这个use 和  string(raw, strlen(raw)+1);
没啥关系,编译优化的话,也可以先销毁吧,不知道有没有这回事
确实应该多一个字符,以便存储结束符
解决方案:15分
C++14 明确了这个方面
[stmt.return]p3
The copy-initialization of the returned entity is sequenced before the destruction of temporaries at the end
of the full-expression established by the operand of the return statement, which, in turn, is sequenced before
the destruction of local variables (6.6) of the block enclosing the return statement.
初始化被返回的对象发生在 return 的表达式中的临时对象被析构之前,而销毁 return 的表达式中的临时对象又发生在析构函数中的局部变量之前
所以顺序一定是
1. 用 string(buff, strlen(buff)) 创建的临时对象初始化被返回的对象
2. 临时对象析构
3. 对象 use 析构
其中程序未必会真的进行 1 和 2 这两个过程,但是在判断程序合法性的时候还是要认为这两个过程是存在的
解决方案:20分
RVO这是上个世纪都已经成熟的技术了,还担心编译器不会很好的优化?
这么说吧,绝大多数人手写汇编都不达不到编译器优化后的水准。
解决方案:15分
char * 通常被当作以0为结束的字符串处理。
std::string 不是以0为结束的字符串。std::string 的内容中可以包括 0 。
std::string str(“abc”);
str.size(), str.length() 不包括最后结束的的 “”0″” 。(结果为 3)
str.c_str(), str.data() 保证返回的结果中,在 str 所存储的内容基础上增加一个 “”\0″”。(它们的返回结果一定可以安全的用于 strxxx 系列函数)(假如 std::string STR; 中所保存的内容中含有””\0″”,那么 STR.length() 与 strlen(STR.c_str()) 将不相等)
str[str.size()] 保证为0 (但不可修改)
str.at(str.size()) 将抛出 std::out_of_range 异常。
解决方案:15分
经过本人思考以后,LZ的写法没错。你删除内存是在‘}’以后,所以没问题

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于 RVO 的一点疑问,求高手指点