提问人:Yarin0600 提问时间:8/25/2023 更新时间:8/25/2023 访问量:74
了解 C++ 中按值传递对象时的复制构造函数和临时对象创建
Understanding Copy Constructor and Temporary Object Creation in C++ When Passing Objects by Value
问:
给定下一个代码:
#include <iostream>
#include <vector>
#include <cstring>
class Person
{
public:
Person(const char *i_Name = "Unknown", int i_Age = 0)
: m_Name(copyFromTo(i_Name, m_Name)), m_Age(i_Age)
{
std::cout << "creating obj " << this << ".\n";
}
Person(const Person &other)
{
std::cout << "Copying from " << &other << " to " << this << ".\n";
this->m_Name = copyFromTo(other.m_Name, this->m_Name);
this->setAge(other.m_Age);
}
~Person()
{
std::cout << "destroying obj " << this << ".\n";
if (m_Name)
{
delete[] m_Name;
}
}
void printDetails() { std::cout << "Hello, my name is " << m_Name << " and I am " << m_Age << " years old.\n"; }
void setAge(int i_Age) { m_Age = i_Age; }
int getAge() const { return m_Age; }
private:
char *copyFromTo(const char *i_Source, char *i_Destination)
{
int sourceSize = strlen(i_Source);
i_Destination = new char[sourceSize + 1];
memcpy(i_Destination, i_Source, sourceSize);
i_Destination[sourceSize] = '\0';
return i_Destination;
}
char *m_Name;
int m_Age;
};
Person birthday(Person person)
{
std::cout << "person's address inside the function " << &person << ".\n";
person.setAge(person.getAge() + 1);
return person;
}
int main()
{
Person person = {"New Person", 24};
birthday(person);
std::cout << "END OF PROGRAM.\n";
}
下一个输出:
输出:
creating obj 0x61fea8.
Copying from 0x61fea8 to 0x61feb8.
person's address inside the function 0x61feb8.
Copying from 0x61feb8 to 0x61feb0. // [temporary object creation]
destroying obj 0x61feb0. // [temporary object destruction]
destroying obj 0x61feb8.
END OF PROGRAM.
destroying obj 0x61fea8.
请注意,程序会在我们输入函数 'birthday' 后立即创建一个对象,因为参数 'person' 是按值传递的。但是,在函数的末尾,还有对复制构造函数的另一次调用,我们正在创建一个额外的临时对象,然后立即销毁该对象。如果我们在销毁本地“person”对象之前销毁它,为什么还需要这个临时对象,而不是 “birthday” 函数中的本地 'person' 对象。
谢谢。
我尝试了谷歌,看到在函数结束之前创建了一个临时对象,但我不明白如果我甚至在销毁函数的第一个本地对象之前就销毁了它,为什么还需要它。它实际上是用来做什么的?
答:
0赞
Klaus
8/25/2023
#1
如果将 main 函数修改为:
int main()
{
Person person = {"New Person", 24};
//birthday(person);
Person anotherPerson = birthday(person);
std::cout << "anotherPerson's address in main " << & anotherPerson << std::endl;
std::cout << "END OF PROGRAM.\n";
}
您将看到“第二个临时”的地址将与局部变量相同。anotherPerson
会发生什么:
如果函数必须返回一个值,则该值必须在函数离开其作用域后有效。当前的 C++ 保证这些副本将被省略,并且局部变量的“新”位置(此处在 的作用域中)将用于此“副本”,实际上它不再是副本。这种优化称为复制省略main
有趣的是,未使用的返回值也会产生未使用的临时值。但这不是 C++ 标准告诉我们的任何事情。这只是对您正在使用的编译器的观察。
顺便说一句:字符串的初始化和副本已完全损坏,并且该变量在未初始化的情况下使用!只需启用所有警告,不要试图变得更好,因为标准行为已经是!std::string
评论
0赞
user17732522
8/26/2023
"有趣的是,未使用的返回值也会产生未使用的临时值。但这不是 C++ 标准告诉我们的任何事情。这只是对您正在使用的编译器的观察结果“:否,此行为已指定,编译器必须遵循它。
上一个:试图找出课程类的复制构造函数
评论
if I destroy it
用这个新对象初始化一个变量,它不会被销毁。该函数承诺返回一个副本,它完全做到了。副本被销毁,因为您不使用它。birthday
birthday
m_name
delete [] m_name;
delete