STL中的string的substr问题

sunnyplain 2009-06-14 05:09:45
不知道大家有没有想过这样的问题

char *buf = "abcdefg";
string s1(buf);
string s2 = s1.substr(0,3);


substr成员函数先要构造一个只包含字符 abc 的一个string的对象,那么s2只是引用了这个对象还是重新构造一个对象,把substr的返回值拷贝到自己的对象里?
...全文
3641 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
Mrloveblue 2012-02-15
  • 打赏
  • 举报
回复
这种东西 测试下 就懂了 应该不是太难的吧
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
等等,调用了,dev居然能编过去,无语了
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 sunnyplain 的回复:]
引用 16 楼 hz_yck 的回复:
引用 14 楼 sunnyplain 的回复:
引用 12 楼 hz_yck 的回复:
C/C++ code# include <iostream>

VS这种对语法要求这么宽的怎么会编不过的,不过倒是重来没用过




是编译不过的,编译错误“d:\test\test.cpp(15): error C4716: “C::operator=” : 必须返回一个值”
难道在dev环境下可以不写那个返回值吗?
[/Quote]

。。。。。抱歉,是因为dev下压根没调用那个函数
Sou2012 2009-06-17
  • 打赏
  • 举报
回复
帮顶!!!
必成桂 2009-06-17
  • 打赏
  • 举报
回复
这里会隐式调用拷贝构造函数。

拷贝构造函数的语义和赋值构造函数的语义是不一样的。
前者是用一个对象初始化一个尚未被初始化的对象
而赋值构造函数的语义是,用一个对象,去赋值另外一个已经存在的对象。

比如说:
string s1 = "hello";
string s2 = s1; // 拷贝构造函数被调用
string s3 = "world";
s3 = s1; //赋值构造函数被调用。


iwong 2009-06-17
  • 打赏
  • 举报
回复
返回的不是引用,所以是重新构造了个对象
mandysss 2009-06-17
  • 打赏
  • 举报
回复
LZ可以再去看看C++ ,关于复制控制成员有明确说明
caremsi 2009-06-16
  • 打赏
  • 举报
回复
up
hz_yck 2009-06-16
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 sunnyplain 的回复:]
引用 12 楼 hz_yck 的回复:
C/C++ code# include <iostream>



都编译不过去,改成如下样子
C/C++ code# include<iostream>usingnamespacestd;classC{public:
C(inti):n(i){cout<<"Construct C"<<i<<endl;}不过倒是重来没用过,
C(constC&c){n=c.n; cout<<"Construct _C"<<c.n<<endl;}~C(){cout<<"Destruct C"<<n<<endl;}voidoperator=(constC&c){cout<<"Copy from C"<<c.n<<"to"<<"C"<<n<<endl;/*n = c.n;*/}//没有变n的值…
[/Quote]

VS这种对语法要求这么宽的怎么会编不过的,不过倒是重来没用过

忘写环境了dev 4.9.9.2,没编过我怎么会写出运行结果的

仔细看dev下的输出,说明g++优化过,没有第一个destruct

以后请仔细看完别人写的再喊
sunnyplain 2009-06-16
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 hz_yck 的回复:]
引用 14 楼 sunnyplain 的回复:
引用 12 楼 hz_yck 的回复:
C/C++ code# include <iostream>

VS这种对语法要求这么宽的怎么会编不过的,不过倒是重来没用过

[/Quote]

是编译不过的,编译错误“d:\test\test.cpp(15): error C4716: “C::operator=” : 必须返回一个值”
难道在dev环境下可以不写那个返回值吗?
hityct1 2009-06-15
  • 打赏
  • 举报
回复
测试一下不就行了:更改s2,再看看s1变不变。
sunnyplain 2009-06-15
  • 打赏
  • 举报
回复
看来大家基本都认为是重新构造了

那么在substr函数里应该是要创建一个string对象的(用来放取到的子串),那这个对象应该是从堆中分配的吧(类似于new出来的),否则的话会因为substr函数的结束那个对象也被释放了。既然是堆中分配出来的,那这个对象什么时候被释放呢?s2是重新构造的,和那个返回的对象已经没关系了。

或者上诉假设有些地方错误?
sunnyplain 2009-06-15
  • 打赏
  • 举报
回复
改成这个样子比较好懂

# include <iostream>
using namespace std;

class C{
public:
C(){n=mark++; cout<<"default construct "<<n<<endl;}
C(const C& c){n = mark++; cout << "copy construct " << c.n << " to "<<n<< endl;}
~C(){cout << "destruct " << n << endl;}
void operator= (const C& c){cout << "asign " << c.n << " to " << n << endl; /*n = c.n;*/}//没有变n的值
private:
int n;
static int mark;
};
int C::mark = 0;

C f(){
C c;
return c;
}

int main(){
C c0=f(); //equals to c0(f())
cout<<"-----------first variable builded--------------"<<endl;
c0 = f();
return 0;
}

输出结果为
default construct 0
copy construct 0 to 1
destruct 0
-----------first variable builded--------------
default construct 2
copy construct 2 to 3
destruct 2
asign 3 to 1
destruct 3
destruct 1
Press any key to continue


说明s1.substr(0,3)的调用时要先创建一个string对象(记为ss1)放置"abc",substr函数结束的时候ss1就应该释放了。返回的时候又要构造一个同样的string对象(记为ss2),然后再将ss2赋值给s2,赋值语句结束后ss2就释放了(这一点可跟踪上面例子中destruct 3的输出时间来验证)
看来还是返回引用比较好吧,这个接口设计不怎么样啊
sunnyplain 2009-06-15
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 hz_yck 的回复:]
C/C++ code# include <iostream>

[/Quote]

都编译不过去,改成如下样子

# include <iostream>

using namespace std;

class C{
public:
C(int i):n(i){cout << "Construct C" << i << endl;}
C(const C& c){n = c.n; cout << "Construct _C" << c.n << endl;}
~C(){cout << "Destruct C" << n << endl;}
void operator= (const C& c){cout << "Copy from C" << c.n << " to " << "C" << n << endl; /*n = c.n;*/}//没有变n的值
private:
int n;
};

C f(int i){
C c(i);
return c;
}

int main(){
C c0 = f(0);
c0 = f(1);
//system("PAUSE");
return 0;
}

后的输出为

Construct C0
Construct _C0
Destruct C0
Construct C1
Construct _C1
Destruct C1
Copy from C1 to C0
Destruct C1
Destruct C0
Press any key to continue


编译环境vs2003
你加了“system("PAUSE"); ”后实际程序还没运行完呢,程序结束的时候还会有析构函数要调用的。
pathuang68 2009-06-15
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 hityct1 的回复:]
测试一下不就行了:更改s2,再看看s1变不变。
[/Quote]

补充,将
string s2 = s1.substr(0,3);
改成
string s1 = s1.substr(0,3);
看看会怎么样?
hz_yck 2009-06-15
  • 打赏
  • 举报
回复
# include <iostream>

using namespace std;

class C{
public:
C(int i):n(i){cout << "Construct C" << i << endl;}
C(const C& c){n = c.n; cout << "Construct _C" << c.n << endl;}
~C(){cout << "Destruct C" << n << endl;}
C& operator= (const C& c){cout << "Copy from C" << c.n << " to " << "C" << n << endl; /*n = c.n;*/}//没有变n的值
private:
int n;
};

C f(int i){
C c(i);
return c;
}

int main(){
C c0 = f(0);
c0 = f(1);
system("PAUSE");
return 0;
}


输出
Construct C0 没有用拷贝构造函数
Construct C1
Copy from C1 to C0
Destruct C1 赋值后就释放了
请按任意键继续. . .
lpf000 2009-06-14
  • 打赏
  • 举报
回复
string s2 = s1.substr(0,3);//
隐式调用拷贝构造函数,string s2后接=实现为一步 调用拷贝构造函数
hjjdebug 2009-06-14
  • 打赏
  • 举报
回复
[Quote=引用楼主 sunnyplain 的帖子:]
不知道大家有没有想过这样的问题

C/C++ code
char *buf = "abcdefg";
string s1(buf);
string s2 = s1.substr(0,3);




substr成员函数先要构造一个只包含字符 abc 的一个string的对象,那么s2只是引用了这个对象还是重新构造一个对象,把substr的返回值拷贝到自己的对象里?
[/Quote]
本人经过研究,认为s2 是通过拷贝构造函数创建的, 而不是'=' 赋值构造。 这样编译器实现一步构造s2.
这也许是编译器优化的结果。 如果你分开写。
string s2; // 先默认构造s2,
s2=s1.substr(0,3) // 此时会调用赋值构造函数。
herman~~ 2009-06-14
  • 打赏
  • 举报
回复
重新构造一个
fairchild811 2009-06-14
  • 打赏
  • 举报
回复
S2应该是重新构造了,然后substr返回的那个再通过拷贝构造函数过来
加载更多回复(5)

64,661

社区成员

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

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