巴扎黑2017-04-17 14:20:29
Compile error because
Without adding <cstdio>, just use printf()
lvalue and rightvalue, the concept of const is unclear, write a copy constructor like A(A& x)
Logically speaking, all allocated stack space will be released after coming out of oneMore... I don’t understand - -, is it because of compiler optimization? The assignment is skipped directly Initialization, while not releasing the space pointed to b in oneMore, will it achieve the effect of initializing b in main?
It’s because you know less about compiler optimization, and the c++ standard does not clearly stipulate this.
First of all, you search for what lvalue and rvalue are. This is a concept that first appeared in the field of compilation and is easy to understand.
Then, let’s look at the following two pieces of code you wrote:
A oneMore(){
A b;
return b;
}
A b = a.oneMore();
Returning an object from a function whose return type is a non-reference type and using this object to assign and initialize another object of the same type should indeed occur twice calling the copy constructor, once when returning the object. =Once during initialization (but not necessarily, see 0x02).
But the function oneMore()
return type is an rvalue. An rvalue is generally considered to be a value that cannot be explicitly changed by user code (except for rvalue references and the move constructor mechanism in C++11). It can only be passed to an lvalue object or a const lvalue reference, so that Guarantee that its content will not be changed.
If an rvalue is passed to a non-const lvalue reference, it means that the user may change the value of the rvalue. So your compiler prompts you for candidate constructor not viable: expects an l-value for 1st argument A(A& x)
. Here l-value means lvalue. You should rewrite it as A(const A& a)
If I remember correctly, C++ Primer should also recommend that when creating a copy constructor, always use the form of A(const A& rhs);
and avoid using A(A& rhs)
. Because the former can cover the latter.
For specific lvalue and rightvalue, const and non-const rules, you can Search The Fucking Web.
A b = a.oneMore();
, if this expression is not optimized, you have to go through the following steps:
Enter the oneMore() function body and create the object to be returned, oneMore()::b. (automatic storage, default constructor)
The function returns and copies the object oneMore()::b to main()::xxx. xxx is a temporary anonymous object that stores the return value of a.oneMore()
. (automatic storage, copy constructor)
A b = xxx
Initialize main()::b (automatic storage, copy constructor) with xxx assignment
It just so happens that the above C++ primers also cover it.
Let’s calculate how much calculation this short expression consumes without optimization: Three constructors, two destructors, if this can save thousands of strings vector. . .
We first perform topological sorting of the variables:
oneMore()::b -> xxx -> main()::b
It can be clearly seen (even the compiler can find it) : OneMore()::b is useless when using xxx, and xxx is useless when using main()::b. So the compiler will do some optimizations to eliminate some unnecessary intermediate step calculations.
I won’t talk about the optimization process and algorithm. Let’s look at the optimization results: the final expression A b = a.oneMore()
There is only one variable main()::b in the entire calculation process, and all operations are applied to this variable. . oneMore()::b, xxx It can be said that there is no creation at all. No creation means no destruction, which saves two constructors and two desctructors. This last expression requires one constructor and zero destructors
Since all operations operate on the same object, the address of this object (although the name is different) is the same no matter where it is printed. It’s all 0x7fff52bfd9a8
.
PHPz2017-04-17 14:20:29
Thank you for the invitation.
Actually, I have answered the original poster’s question several times. It may be because there are not many people on C++ in SF. .
I want to make some digressions here. Regarding the original poster’s learning method, for C++, if you want to understand it quickly, writing a program is necessary, but this is not how to analyze the problem.
C++ is a relatively low-level language, and the compilation result is directly binary, so we generally understand the principles through assembly as the fastest way.
Actually, I have just studied this issue a few months ago.
Note: The following codes are in debug mode and have not been optimized. (In the case of optimization, the compiler will split parameters according to the complexity of the type, and the pointer on the heap will be returned directly without copying, etc. This is a compiler behavior and has nothing to do with the C++ language itself.)
std::string test2()
{
std::string s="222";
return s;
}
void main()
{
std::string s1=test2();
std::cout<<s1<<std::endl;
}
We know that the memory applied for on the stack must be released as the function returns (because the stack needs to be flattened), so the above function is analyzed in assembly. The pseudo code is roughly as follows:
std::string test2()
{
//里面执行stirng的构造函数
auto s = new stringObject("123123");
//dosomething;
//返回前要平栈,但是这个复杂对象又是一个返回值
//所以要先复制到返回值的地方
auto s1=new stringObjectForm(s);
//复制完成后要对本栈内的string析构,进行内存的释放
delete s;
return s1;
}
Then s1 here in the return value is actually the memory applied for inside.
As for the reference parameter value transfer, it is similar to the above process, but the difference is that the caller first applies for memory and then passes it to the callee for copying.
怪我咯2017-04-17 14:20:29
Hello, your code runs as follows on my machine and there are no major problems.
For your second question about the address, see the picture below. I laughed....
My compilation environment is mainly VC++, as follows
I used the Linux g++ compiler again to test your program.
One thing, there is a serious error in the coding style of the program. I corrected the irregularities and then compiled it successfully. g++ xxxx.cpp
The result of running the program shows that the address is correct. The copy constructor is just not called. The specific reason is unknown.
Suggestion: Even if the program is small, please standardize the code format.
PHPz2017-04-17 14:20:29
a.oneMore()
The function returns an rvalue, you need to declare a copy constructor like this
A(const A& x){
printf("Copy!\n");
}
PHP中文网2017-04-17 14:20:29
In addition, I also discovered a strange feature, that is, I tried to print the address of this b in oneMore and main respectively:
A oneMore(){
A b("lisi");
printf("%p\n", &b);
return b;
}
int main(int argc, char* argv[]) {
A a("zhangsan");
A b = a.oneMore();
printf("%p\n", &b);
printf("1314\n");
return 0;
}
The result is that these two results are the same... that is to say, they actually point to the same memory:
/Users/zhangzhimin/Library/Caches/CLion2016.2/cmake/generated/geek-ef0ba4bc/ef0ba4bc/Debug/geek -wall
zhangsanchuangjianle
lisichuangjianle
0x7fff52bfd9a8
0x7fff52bfd9a8
1314
lisixiaohuile
zhangsanxiaohuile
Process finished with exit code 0
It stands to reason that all allocated stack space will be released after coming out of oneMore... I don’t understand - -, is it due to compiler optimization? The assignment initialization is skipped directly, and at the same time Without releasing the space pointing to b in oneMore, can we achieve the effect of initializing b in main?