C++ 在c++;
编辑:我知道在这种情况下,如果它是一个实际的类,我最好不要将字符串放在堆上。然而,这只是一个示例代码,以确保我理解该理论。实际代码将是一棵红黑树,所有节点都存储在堆上 在继续之前,我希望确保这些基本思想是正确的(我来自Java/Python背景)。我一直在网上搜索,但还没有找到这个问题的具体答案 当您重新分配指向新对象的指针时,是否必须首先对旧对象调用delete以避免内存泄漏?我的直觉告诉我是的,但在继续之前我需要一个具体的答案 例如,假设有一个类存储了指向字符串的指针C++ 在c++;,c++,memory-management,pointers,C++,Memory Management,Pointers,编辑:我知道在这种情况下,如果它是一个实际的类,我最好不要将字符串放在堆上。然而,这只是一个示例代码,以确保我理解该理论。实际代码将是一棵红黑树,所有节点都存储在堆上 在继续之前,我希望确保这些基本思想是正确的(我来自Java/Python背景)。我一直在网上搜索,但还没有找到这个问题的具体答案 当您重新分配指向新对象的指针时,是否必须首先对旧对象调用delete以避免内存泄漏?我的直觉告诉我是的,但在继续之前我需要一个具体的答案 例如,假设有一个类存储了指向字符串的指针 class MyCla
class MyClass
{
private:
std::string *str;
public:
MyClass (const std::string &_str)
{
str=new std::string(_str);
}
void ChangeString(const std::string &_str)
{
// I am wondering if this is correct?
delete str;
str = new std::string(_str)
/*
* or could you simply do it like:
* str = _str;
*/
}
....
在ChangeString方法中,哪一个是正确的
我想如果你不在第二种方式中使用new关键字,我会挂断电话,它仍然会像你期望的那样编译和运行。这是否只是覆盖了指针指向的数据?或者它还有别的作用吗
任何建议都将不胜感激:D三点意见:
你也需要一个析构函数
~MyClass()
{
delete str;
}
在这种情况下,实际上不需要使用堆分配的内存。您可以执行以下操作:
class MyClass {
private:
std::string str;
public:
MyClass (const std::string &_str) {
str= _str;
}
void ChangeString(const std::string &_str) {
str = _str;
};
您不能执行已注释掉的版本。那将是内存泄漏。Java处理这个问题是因为它有垃圾收集。C++没有这个特性。 为什么你认为你需要在类中存储一个指向字符串的指针?指向C++集合的指针(如字符串)实际上很少需要。几乎可以肯定,您的班级应该是这样的:
class MyClass
{
private:
std::string str;
public:
MyClass (const std::string & astr) : str( astr )
{
}
void ChangeString(const std::string & astr)
{
str = astr;
}
....
};
当您重新分配指向新对象的指针时,是否必须首先对旧对象调用delete以避免内存泄漏?我的直觉告诉我是的,但在继续之前我需要一个具体的答案
对。如果是原始指针,则必须先删除旧对象
当您分配一个新值时,有一些智能指针类可以为您执行此操作。只需在此处指出,但是
str = _str;
无法编译(您试图将_str(通过引用传递的字符串的值)分配给str(字符串的地址)。如果你想这样做,你可以写:
str = &_str;
(您必须更改_str或str,以便constnest匹配)
但是,正如你的直觉告诉你的那样,你会泄露str已经指向的任何字符串对象的内存
正如前面指出的,当你在C++中添加一个变量给你的时候,你必须考虑变量是由对象拥有还是由其他东西拥有。p> 如果它是由对象拥有的,那么您最好将它存储为一个值,并复制周围的内容(但是您需要确保复制不会发生在您的后面)
它是不被拥有的,那么你可以将它存储为一个指针,并且你不一定需要一直复制东西 其他人会比我更好地解释这一点,因为我真的无法接受。 我最后经常做的是编写这样的代码:class Foo {
private :
Bar & dep_bar_;
Baz & dep_baz_;
Bing * p_bing_;
public:
Foo(Bar & dep_bar, Baz & dep_baz) : dep_bar_(dep_bar), dep_baz_(dep_baz) {
p_bing = new Bing(...);
}
~Foo() {
delete p_bing;
}
也就是说,如果一个对象依赖于“Java”/“Ioc”意义上的某个对象(这些对象存在于其他地方,您不是在创建它,您只想对其调用方法),我将使用dep_xxxx将依赖项存储为引用
如果我创建对象,我将使用带有p_uu前缀的指针
这只是为了让代码更“即时”。我不确定这是否有用
就我的2c
祝你在内存管理方面好运,你是对的,它是来自Java的棘手部分;在你适应之前不要写代码,否则你会花很多时间去追逐塞戈尔特
希望这有帮助 如果您来自垃圾收集语言的背景,并且发现自己确实需要使用堆内存,我建议使用boost共享指针。您可以这样使用它们:
#include <boost/shared_ptr.hpp>
...
boost::shared_ptr<MyClass> myPointer = boost::shared_ptr<MyClass>(new MyClass());
#包括
...
boost::shared_ptr myPointer=boost::shared_ptr(new MyClass());
myPointer的语言语义与常规指针几乎相同,但shared_ptr使用引用计数来确定何时删除它引用的对象。基本上是自己动手的垃圾收集。文档如下:如果必须取消分配旧实例并创建另一个实例,则应首先确保创建新对象成功:
void reset(const std::string& str)
{
std::string* tmp = new std::string(str);
delete m_str;
m_str = tmp;
}
如果您先调用delete,然后创建一个新实例会抛出一个异常,那么类实例将留下一个悬空指针。例如,析构函数可能会再次尝试删除指针(未定义的行为)
您还可以通过将指针设置为NULL来避免这种情况,但上面的方法更好:如果重置失败,对象将保留其原始值
至于代码注释中的问题
*str = _str;
这将是正确的做法。这是正常的字符串赋值
str = &_str;
这将是分配指针,并且是完全错误的。您将泄漏先前由
str
指向的字符串实例。更糟糕的是,传递给函数的字符串很可能首先没有分配new
(不应该混合指向动态分配对象和自动对象的指针)。此外,您可能正在存储一个字符串对象的地址,该对象的生存期以函数调用结束(如果const引用绑定到一个临时对象)。我将为您编写一个类
class A
{
Foo * foo; // private by default
public:
A(Foo * foo_): foo(foo_) {}
A(): foo(0) {} // in case you need a no-arguments ("default") constructor
A(const A &a):foo(new Foo(a.foo)) {} // this is tricky; explanation below
A& operator=(const &A a) { foo = new Foo(a.foo); return *this; }
void setFoo(Foo * foo_) { delete foo; foo = foo_; }
~A() { delete foo; }
}
对于包含这样的资源的类,复制构造函数assignment oper