【发布时间】:2016-08-24 04:25:07
【问题描述】:
假设我正在用 C++ 编写一个字符串类(我知道我可以使用该库)。字符串长度是可变的,存储空间在构造函数中动态分配并在析构函数中释放。当main函数调用c=a+b(a,b,c是字符串)时,operator+成员函数会创建一个临时对象来存储连接的字符串a+b,将其返回给main函数,然后@调用987654331@成员函数释放原来存储在c中的字符串,并将临时字符串a+b中的数据复制到c,最后临时a+b被销毁。
我想知道是否有办法实现这一点:我希望它交换a+b 和c 的数据指针,而不是让operator= 将数据从a+b 复制到c ,这样当a+b被破坏时,它会破坏c中的原始数据(这就是我们想要的),而c现在不需要复制a+b的结果。
我知道编写一个 2 参数成员函数 setToStrcat 并调用 c.setToStrcat(a,b) 可以做到这一点。例如,函数可以编码为:
void String::setToStrcat(const String& a,const String& b){
String tmp(a.len+b.len); int i,j;
for(i=0;i<a.len;i++) tmp[i]=a[i];
for(j=0;j<b.len;i++,j++) tmp[i]=b[j];
tmp[i]='\0'; this->swap(tmp);
}
void String::swap(String& a){
int n=len; len=a.len; a.len=n;
char *s=str; str=a.str; a.str=s;
}
我省略了构造函数(分配len+1 字符型空格)和operator[](返回ith 字符的引用)的定义。 swap函数将*this和tmp之间的数据指针和长度变量进行交换,这样当tmp在交换后被破坏时,实际上是原来存储在*this中的数据(String c在main 函数)被破坏。 *this 现在拥有的 (c.str) 是串联的字符串 a+b。
我想知道是否有办法将c=a+b 的性能优化到相同的水平。我尝试了c.swap(a+b) 并将a+b 的返回类型更改为String&,但我收到警告(对局部变量的引用)并且GDB 显示临时在交换发生之前被破坏,而我想要另一种方式。
我认为我的问题很笼统。在 C++ 编程中,我们经常需要一个临时对象来存储函数的结果,但是当我们将它分配给主函数中的另一个对象时,我们可以不复制数据而是使用(更快)指针交换吗?有什么巧妙的方法可以做到这一点?
【问题讨论】:
-
有一个巧妙的方法:) 搜索移动语义,更具体地说:移动构造函数和移动赋值运算符。
-
还没听说过移动语义? Read up.
-
你所说的看起来像copy elision。在 C++ 中,它会从 C++17 开始得到保证。
-
在我的编译器中,如果我执行
String c=a+b;,则不会调用operator=(我猜是指针值和长度变量的逐字节复制)。这是复制省略。但如果我执行String c; c=a+b;,则会调用operator=。这是正确的,因为否则 c 中的原始数据(空字符串)不会被释放。我想要的只是一个基于交换的副本(交换a+b和c的数据指针),而不是没有副本(在这种情况下这是不正确的)。