C++ C+中的字符串+;

C++ C+中的字符串+;,c++,string,mutable,C++,String,Mutable,关于C中的字符串,我有以下问题++ 1> >哪一个是更好的选择(考虑性能),为什么 一, 或 二, 2> > < >当较大的字符串被复制到较小的字符串时,C++如何精确地处理内存管理?C++字符串是否可变?< /P> string a; a = "hello!"; 2操作:调用默认构造函数std:string(),然后调用运算符::= string *a; a = new string("hello!"); ... delete(a); 只有一个操作:调用构造函数std:string(con

关于C中的字符串,我有以下问题++

1> >哪一个是更好的选择(考虑性能),为什么

一,

二,

2> >

< >当较大的字符串被复制到较小的字符串时,C++如何精确地处理内存管理?C++字符串是否可变?< /P>
string a;
a = "hello!";
2操作:调用默认构造函数std:string(),然后调用运算符::=

string *a; a = new string("hello!"); ... delete(a);
只有一个操作:调用构造函数std:string(constchar*),但不要忘记释放指针

那怎么办
字符串a(“你好”)

几乎没有必要或希望说

string * s = new string("hello");
毕竟,你(几乎)永远不会说:

int * i = new int(42);
你应该说

string s( "hello" );


是的,C++字符串是可变的。

< P>有没有一个特殊的原因,为什么你总是使用赋值而不是初始化呢?那就是,你为什么不写信呢

string a = "Hello";
等等。?这避免了默认的构造,只是在语义上更有意义。仅仅为了在堆上分配字符串而创建一个指向字符串的指针是没有意义的,也就是说,您的案例2没有意义,而且效率稍低

关于最后一个问题,是的,C++中的字符串是可变的,除非声明为“代码> const .< /P> < P>在1.1中,您的字符串成员(包括指向数据的指针)被保存在堆栈中,当<代码> A<代码>范围之外时,类实例占用的内存被释放。 在案例1.2中,成员的内存也是从堆中动态分配的

char*
常量指定给字符串时,将对包含数据的内存进行
realloc
,以适应新数据

通过调用
string::capacity()
,您可以看到分配了多少内存

调用
字符串a(“hello”)
时,将在构造函数中分配内存

构造函数和赋值运算符都在内部调用相同的方法来分配内存,并在其中复制新数据。

如果您查看STL字符串类的方法(我相信SGI文档符合规范),许多方法都列出了复杂性保证。我相信许多复杂性保证都是故意留下模糊的,以允许不同的实现。我认为有些实现实际上使用了修改时复制的方法,这样将一个字符串分配给另一个字符串是一个固定时间操作,但是当您尝试修改其中一个实例时,可能会产生意外的成本。但不确定这在现代STL中是否仍然正确

您还应该检查
capacity()
函数,该函数将告诉您在强制重新分配内存之前可以放入给定字符串实例的最大字符串长度。如果您知道以后要在变量中存储一个大字符串,还可以使用
reserve()
将其重新分配到特定的数量


正如其他人所说,就您的示例而言,您应该更喜欢初始化而不是其他方法,以避免创建临时对象。

以下是一个幼稚的编译器应该做的。当然,只要它不改变程序的行为,编译器就可以自由地进行任何优化

string a;
a = "hello!";
首先,初始化一个包含空字符串的。(将长度设置为0,并执行一个或两个其他操作)。然后指定一个新值,覆盖已设置的长度值。它可能还必须执行检查,以查看当前缓冲区有多大,以及是否应分配更多内存

string *a;
a = new string("hello!");
...
delete(a);
调用new需要操作系统和内存分配器找到一块空闲内存。太慢了。然后立即初始化它,这样就不会像在第一个版本中那样两次分配任何内容或要求调整缓冲区的大小。 然后一些不好的事情发生了,您忘记调用delete,并且除了一个分配速度非常慢的字符串之外,还有一个内存泄漏。所以这很糟糕

string a;
a = "less"; 
a = "moreeeeeee";
与第一种情况一样,首先初始化一个包含空字符串的字符串。然后分配一个新字符串,然后分配另一个。其中每一个都可能需要调用new来分配更多内存。每行还需要指定长度,可能还需要指定其他内部变量

通常,您会这样分配它:

string a = "hello";
一行,执行一次初始化,而不是首先默认初始化,然后分配所需的值

它还可以最大限度地减少错误,因为程序中的任何地方都没有无意义的空字符串。如果字符串存在,则它包含所需的值

关于内存管理,谷歌RAII。
简而言之,string在内部调用new/delete来调整其缓冲区的大小。这意味着您永远不需要使用new分配字符串。string对象具有固定的大小,并被设计为在堆栈上分配,以便在析构函数超出范围时自动调用它。然后,析构函数保证释放所有分配的内存。这样,您就不必在用户代码中使用new/delete,这意味着您不会泄漏内存。

直接在堆中创建字符串通常不是一个好主意,就像创建基类型一样。这不值得,因为对象可以轻松地留在堆栈上,并且它拥有高效复制所需的所有复制构造函数和赋值运算符

std:string本身在堆中有一个缓冲区,可以由多个字符串共享,具体取决于实现

例如,通过Microsoft的STL实现,您可以做到:

string a = "Hello!";
string b = a;
两个字符串将共享相同的缓冲区,直到您更改它:

a = "Something else!";
这就是为什么将c_str()存储起来供以后使用是非常糟糕的;c_str()只保证在再次调用该字符串对象之前的有效性

这会导致非常严重的并发错误,如果在多线程应用程序中使用共享功能,则需要使用define关闭这些共享功能。

   string a("hello!");
比其他任何东西都快。

你来了
string a = "hello";
string a = "Hello!";
string b = a;
a = "Something else!";
   string a("hello!");
string a;
a = "less"; 
a = "moreeeeeee";