C++对象析构与return语句的先后关系引发的疑问?

oldgold 2016-11-09 02:06:53
各位大神,小菜我目前在学习一些开源项目,遇到一些不懂的地方;来请教一下。

开源项目地址:https://github.com/baidu/tera (百度开源的分布式大数据系统)

源码文件地址:https://github.com/baidu/tera/blob/master/src/common/mutex.h

一个互斥锁的封装,形如(我简化了一下,看看大意吧),


#include <pthread.h>

class Mutex {
public:
Mutex() {
pthread_mutex_init(&mu_, NULL);
}
~Mutex() {
pthread_mutex_destroy(&mu_);
}
void Lock() {
pthread_mutex_lock(&mu_);
}
void Unlock() {
pthread_mutex_unlock(&mu_);
}
private:
pthread_mutex_t mu_;
};

class MutexLock {
public:
MutexLock(Mutex *mu): mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex *mu_;
};

class Test {
public:
Test():c_(0) {
}
void add(int i) {
MutexLock l(&mu_);
c_ += i;
}
int get() {
MutexLock l(&mu_);
return c_;
}
private:
int c_;
Mutex mu_;
};


在class Test中,
    
void add(int i) {
MutexLock l(&mu_);
c_ += i;
}
int get() {
MutexLock l(&mu_);
return c_;
}

为什么这么做是有效的?以get为例,是说编译器先把c_的值暂存为tmp变量,释放了mutex以后再返回tmp吗?
MutexLock对象 l 和return语句谁先谁后,是怎么工作的?标准是怎么定义的,有哪些资料可以参考呢?

谢谢。
...全文
931 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
paschen 版主 2016-11-10
  • 打赏
  • 举报
回复
《深入探索C++对象模型》
paschen 版主 2016-11-10
  • 打赏
  • 举报
回复
会先将这个对象复制到返回接收的那个对象,然后执行该对象的析构
fefe82 2016-11-10
  • 打赏
  • 举报
回复 2
引用 4 楼 oldgold 的回复:
求详解下。。基础有限,直接来英文标准文档,并不太懂。
return 一个值(不是引用)的时候,会发生一个拷贝即将 return 后面的表达式的值拷贝一份成为返回值。这是发生在 return 语句内部的。之后才是控制离开当前函数,此时局部变量才会析构。
ri_aje 2016-11-10
  • 打赏
  • 举报
回复
c_ 放在 eax 里面,然后析构 l,然后 ret
赵4老师 2016-11-09
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察! 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
oldgold 2016-11-09
  • 打赏
  • 举报
回复
求详解下。。基础有限,直接来英文标准文档,并不太懂。
pengzhixi 2016-11-09
  • 打赏
  • 举报
回复
在这个return 语句里面会完成c_的临时存储以及l的析构
fefe82 2016-11-09
  • 打赏
  • 举报
回复
6.6.3 The return statement [stmt.return] 1 A function returns to its caller by the return statement. 2 A return statement with neither an expression nor a braced-init-list can be used only in functions that do not return a value, that is, a function with the return type cv void, a constructor (12.1), or a destructor (12.4). A return statement with an expression of non-void type can be used only in functions returning a value; the value of the expression is returned to the caller of the function. The value of the expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy or move of a temporary object (12.2). [ Note: A copy or move operation associated with a return statement may be elided or considered as an rvalue for the purpose of overload resolution in selecting a constructor (12.8). — end note ] A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization (8.5.4) from the specified initializer list. [ Example: std::pair<std::string,int> f(const char* p, int x) { return {p,x}; } — end example ] Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function. 3 A return statement with an expression of type void can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller. 4 Standard conversions [conv] 3 An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed, for some invented temporary variable t (8.5). 6 The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type (8.3.2), an xvalue if T is an rvalue reference to object type, and a prvalue otherwise. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.
fefe82 2016-11-09
  • 打赏
  • 举报
回复
3.7.3 Automatic storage duration [basic.stc.auto] 1 Block-scope variables explicitly declared register or not explicitly declared static or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits. 2 [ Note: These variables are initialized and destroyed as described in 6.7. — end note ] 3 If a variable with automatic storage duration has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8. 6.7 Declaration statement [stmt.dcl] 2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧