最近,我对使用字符串数据类型的new关键字感到困惑。你可以试着澄清一下吗
以下字符串初始化之间的区别是什么:
1)
string* name = new string("abc") ;
....
delete name;
2)
string name = "abc";
建议使用new关键字,因为string中的值是存储在堆中作为std::string
的内部缓冲区的任何值。如果有人用存储位置解释它会很好。
返回字符串与字符串*
之间的区别是什么string* name()
{
string* name = new string("abc") ;
return name;
}
string name()
{
string name = "abc";
return name;
}
答案 0 :(得分:1)
string
是在当前作用域中创建的实际字符串,当作用域退出时,它将自动清除。
void function() {
{ // a scope
string test = "hi";
}
// test is destroyed here and cannot be used.
}
string*
是指向未绑定到当前范围的字符串的指针。指针开始无效(通常由用户分配nullptr
,这意味着它不指向任何内容),并且您需要为其分配内存位置;如果不是,那么访问它将是一个错误。当你使用new
并为指针赋值时,你有一个位于堆上而不是当前作用域的字符串,你需要手动delete
,否则内存是泄漏。您可以将指针包装在智能指针中,以使其自动删除。
void function() {
{
string *test = new string("hi");
}
// test is *not* destroyed and memory was leaked
}
void function() {
unique_ptr<string> test;
{
test = unique_ptr<string>( new string("hi") );
}
} // test is deleted when the function exits and the unique_ptr goes out of scope.
避免使用new
分配对象的主要原因是它比使用堆栈中的项目慢,而使用 new
的主要原因是它可能更快地传递指向对象的指针而不是复制对象。
但是,虽然复制字符串的速度可能很慢,但您也可以移动字符串,这样可以加快速度。
移动字符串只需将字符串A的内部缓冲区重新定位到字符串B
string function() {
string test = "abcdefg";
return test; // when test is returned, it is moved to the calling function.
}
您也可以显式移动字符串。
string A = "hello";
string B( std::move(A) );
// A is invalid, and B contains "hello"
通常std :: strings不是自己创建的,而是它们所在的结构或类可能是。
使用指针的一个例子,我可能有一个特殊的类,我传递给不同的函数:
class MyClass {
string a;
public:
const string *function1() { return &a; }
const string &function2() { return a; }
string function3() { return a; }
}
MyClass::function1
给了我一个指向字符串的const指针,意味着没有复制数据,我只能读取字符串的值。
MyClass::function2
基本上与function1做同样的事情,但它使用引用代替,引用就像指针但它们必须始终包含有效目标。引用通常用于C ++ over pointers。
MyClass::function3
返回字符串的副本,外部函数可以修改它,它不会影响类中的字符串。
答案 1 :(得分:1)
有几个理由比第一种方法更喜欢第二种方法:
最重要的原因:string
是string
,期间。 string*
可以指向string
,也可以指向NULL
/ nullptr
,也可以指向内存中的随机位置。因此,您应该尽可能使用普通的string
而不是string*
,因为使用它们不容易出错。
声明string
对象将其放在堆栈上,这意味着它会在离开作用域时自动清理。使用new
意味着您现在必须手动清理已分配的内存。
new
是一个相对较慢的操作。使用堆栈变量要快得多。
虽然string
将其数据存储在堆上,但在堆上分配string
本身仍会增加另一级别的间接。
答案 2 :(得分:0)
如果我们使用new运算符,则将在堆内存中创建对象,并且引用指针将位于堆栈中。在您的示例中,
string* name()
{
string* name = new string("abc") ;
return name;
}
name是一个存储在堆栈中的指针变量,它包含字符串对象的地址。实际对象存储在堆中。所以在方法执行后它不会被销毁。调用方法将获取对象的地址,我们可以使用它来引用它。我们需要使用&#39; delete&#39;来释放字符串对象内存。关键字。
例如:
delete name;
如果我们定义一个没有new运算符的字符串,它将在堆栈本身中创建,并在方法执行结束时自动销毁。考虑一下这个例子,
string name()
{
string name = "abc";
return name;
}
这里将在方法名称的堆栈框架中创建一个对象,在方法执行完毕后,它将被销毁。
使用上述功能的语句将类似于
string a = name();
这里将调用字符串类的operator =()方法,并在调用函数的堆栈帧中创建一个新对象。
希望这会有所帮助