Perl确实功能很方便阿

哦……可我在47楼不是解释了么……
强烈谴责在perl版讨论C++的行为
呵呵,我说到是对我程序结果进行细节分析
你没见我那里的结果的地址有多次改变吗?
就是为什么改变,分别代表什么做下分析

你47楼的解释,我觉得还不能说明问题,或者我无法对号入座,谢谢了
兄台搞点有讨论头的perl来说说嘛

我觉得perl很多地方太黑盒了,你完全不了解其机理
C++很多地方,你得抠,不抠用不对啊

所以Lonki兄说,c版很多都是对语法的讨论,而perl版就不是了
底层的你没法讨论,原因有一些的


QUOTE:
原帖由 shaver 于 2007-9-30 11:46 发表
写代码测试了一下
#include
#include
using namespace std;

inline int print_str_addr(string env,const string& str)
{
  cout

有意思.
你的代码并没有"完全"证明值传递仅在写时拷贝, 其中仅仅考虑了c_str()得到的string内部char *的地址, 而不是string变量自身的地址.
来分析一段简单的代码吧:

#include <iostream>
#include <string>
using namespace std;


void testPassByValue(string str)
{
    cout << endl << "Inside testPassByValue:" << endl;
    cout << "str = " << str << ", str address: " << &str << ", str.c_str(): " << (void *)str.c_str() << endl;
    
    str[0] = 'd';
    cout << "str = " << str << ", str address: " << &str << ", str.c_str(): " << (void *)str.c_str() << endl;   
}


void testPassByRef(string &str)
{
    cout << endl << "Inside testPassByRef:" << endl;
    cout << "str = " << str << ", str address: " << &str << ", str.c_str(): " << (void *)str.c_str() << endl;   
    
    str[0] = 'd';
    cout << "str = " << str << ", str address: " << &str << ", str.c_str(): " << (void *)str.c_str() << endl;   
}


int main(int argc, char *argv[])
{
    string str1("abc");
    cout << "str1 = " << str1 << ", str1 address: " << &str1 << ", str1.c_str(): " << (void *)str1.c_str() << endl;
    
    testPassByValue(str1);
    testPassByRef(str1);
        
    system("pause");
    return 0;
}



输出结果如下, #后为注释
str1 = abc, str1 address: 0x22ff50, str1.c_str(): 0x3e24cc    ### str1真实地址是50, 内部char *的地址是cc

Inside testPassByValue:
str = abc, str address: 0x22ff40, str.c_str(): 0x3e24cc          ### 值传递, 此时str的地址已改变, 但内部char *仍然是cc   !!1!!
str = dbc, str address: 0x22ff40, str.c_str(): 0x3e24e4         ### 写str, 内部char *改变为e4                                     !!2!!

Inside testPassByRef:
str = abc, str address: 0x22ff50, str.c_str(): 0x3e24cc          ### 引用传递, 此时str的地址同外部str1的地址50, 内部同cc
str = dbc, str address: 0x22ff50, str.c_str(): 0x3e24cc          ### 写str, 内部char *仍然是cc, 因为是修改的原变量

分析:
对于引用传递, 结果毋庸置疑; 关键点在值传递, 请看带!!!的2行.

!!1!!
进入testPassByValue后, str的地址已改变, 说明它是一个拷贝后的变量, 下文用__str来称呼它.
但为什么__str的char *仍同原str1呢? 因为string内部保存的是char *这个地址.
在str1中保存了cc这个char *起始地址, __str仅拷贝了cc这个数值, 所以__str的char *仍然是cc.

!!2!!
修改__str中的某个字符(总长度未改变), 但内部char *却发生了变化, 这算是写时拷贝吧.



综上, func(string str)是会增大开销的. 这个开销拿string来说不明显, 因为string仅拷贝了char *的地址.
如果是复杂Class类型, 那么开销是很可观的.


QUOTE:
原帖由 perljoker 于 2007-9-30 13:18 发表
大家都是讨论技术嘛,没有喧宾夺主就好

我在45楼的帖子里面的程序段,cout

是的. 55楼的代码同样可以看出.
&str是变量自身的地址.
str.c_str()返回一个const char *, 是string内部char数组的地址.

看下string的内部实现, 一目了然.

gcc的一些定义:

      struct _Alloc_hider : _Alloc
      {
        _Alloc_hider(_CharT* __dat, const _Alloc& __a)
        : _Alloc(__a), _M_p(__dat) { }

        _CharT* _M_p; // The actual data.
      };


mutable _Alloc_hider        _M_dataplus;
c_str() const { return _M_data(); }
_CharT*     _M_data() const      { return  _M_dataplus._M_p; }
看来string类的设计比原来想像的还要复杂

我觉得是这样,string类在做值传递和=号重载复制,都采用了简省机制
对于内部字符串的复制采用了对地址的复制,减少了空间的消耗,默认操作也应该是const型
这个看起来很像所谓的“浅拷贝”
然后,在对该串进行修改的时候,string类又灵活的开辟了新空间,使指针重新定向(机理偶不明)
实际上对字符串进行了copy,就成为了“深拷贝”

莫非是一种妥协机制?并且在简单复制时,如,string str1=str2时,减少空间消耗?
看来,string类内部还是有些自我调整的


QUOTE:
原帖由 perljoker 于 2007-9-30 14:07 发表
呵呵,我说到是对我程序结果进行细节分析
你没见我那里的结果的地址有多次改变吗?
就是为什么改变,分别代表什么做下分析

你47楼的解释,我觉得还不能说明问题,或者我无法对号入座,谢谢了

呵呵,没有看懂你的结果有什么需要分析的。
&str,是取这个字符串变量的地址,而不是“字符串内容”的地址;不管其内容如何变化,变量地址不改变,或者即使指向同一个字符串内容,但不同的变量地址不同,这很正常啊


QUOTE:
原帖由 shaver 于 2007-9-30 15:11 发表


呵呵,没有看懂你的结果有什么需要分析的。
&str,是取这个字符串变量的地址,而不是“字符串内容”的地址;不管其内容如何变化,变量地址不改变,或者即使指向同一个字符串内容,但不同的变量地址不同,这 ...

从我那个结果,可以看出一些东西的

比如说,你函数调用都使用了值传递,导致我多处&str结果的不一样,实际上是对对象的重构了,这就是开销
但是,所有的对该字符串的指向却又都是一样的,如果对该串进行操作,string貌似自动生成新的string
在你使用fun的时候,虽然显示原字符串的地址,但是对象仍然是新的

所以,我感觉,使用string的时候,宁可使用string&或者const string&的形式
这样可以避免无意的修改,同时也不需要string“自动调整”,这样写要比string合适
除非,真的string很简单,就无所谓了


QUOTE:
原帖由 perljoker 于 2007-9-30 15:10 发表
看来string类的设计比原来想像的还要复杂

我觉得是这样,string类在做值传递和=号重载复制,都采用了简省机制
对于内部字符串的复制采用了对地址的复制,减少了空间的消耗,默认操作也应该是const型
这个看 ...

恩, 其实这就是string内部的Copy-On-Write 写时拷贝, 通过一个引用计数来实现
_M_is_shared() const  { return this->_M_refcount > 0; }


这个讨论貌似比较深入了哦...