- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设我们有一个类 X,它没有有一个重载的 operator=()
函数。
class X {
int n;
X() {n = 0;}
X(int _n) {n = _n;}
};
int main() {
X a; // (1) an object gets constructed here
// more code...
a = X(7); // (2) another object gets constructed here (?)
// some more code...
a = X(12); // (3) yet another object constructed here (?)
return 0;
}
是否在(2)处构造了一个新对象?如果是,在 (1) 处构造的旧对象会发生什么情况?它是自动销毁还是释放(是哪个)?是否被覆盖?
在代码 (3) 的下方发生了什么?
最重要的是,是否有可能通过编写上述代码导致内存泄漏?
最佳答案
您需要了解的是,作为新手,您不知道编译器生成的许多“隐式”代码。我们将使用您的 class X
代码作为直接示例:
class X {
int n;
public: //You didn't include this, but this won't work at all unless your constructors are public
X() {n = 0;}
X(int _n) {n = _n;}
};
在代码变成目标代码之前,但在你的编译器得到你的类定义之后,它会将你的类转换成看起来(大致)像这样的东西:
class X {
int n;
public:
X() {n = 0;} //Default-Constructor
X(int _n) {n = _n;} //Other Constructor
//GENERATED BY COMPILER
X(X const& x) {n = x.n;} //Copy-Constructor
X(X && x) {n = x.n;} //Move-Constructor
X & operator=(X const& x) {n = x.n; return *this;} //Copy-Assignment
X & operator=(X && x) {n = x.n; return *this;} //Move-Assignment
~X() noexcept {} //Destructor
};
关于何时自动创建这些成员的规则并不是很明显 (A good starting reference here),但现在,您可以相信,在这种情况下,这正是发生的事情。
因此,在您的 main
函数中,让我们回顾一下发生了什么,并通过注释引起注意的细节:
int main() {
X a; //Default-Constructor called
a = X(7);//Other Constructor called, then Move-Assignment operator called,
//then Destructor called on temporary created by `X(7)`
a = X(12); //Same as previous line
return 0;
//Destructor called on `a`
}
我们将添加更多行来显示这些调用的大部分(如果不是全部)各种排列:
int main() {
X a; //Default-Constructor
X b = a; //Copy-Constructor (uses copy-elision to avoid calling Default + copy-assign)
X c(5); //Other Constructor
X d{7}; //Also Other Constructor
X e(); //Declares a function! Probably not what you intended!
X f{}; //Default-Constructor
X g = X(8); //Other Constructor (uses copy-elision to avoid calling Other + move-assign + Destructor)
X h = std::move(b); //Move-Constructor (uses copy-elision to avoid calling Default + move-assign)
b = c; //Copy-assignment
b = std::move(d); //Move-assignment
d = X{15}; //Other Constructor, then Move-Assignment, then Destructor on `X{15}`.
//e = f; //Will not compile because `e` is a function declaration!
return 0;
//Destructor on `h`
//Destructor on `g`
//Destructor on `f`
//Destructor will NOT be called on `e` because `e` was a function declaration,
//not an object, and thus has nothing to clean up!
//Destructor on `d`
//Destructor on `c`
//Destructor on `b`
//Destructor on `a`
}
这应该涵盖基础知识。
And most importantly, is there ever a chance of causing a memory leak by writing code like in the above?
正如所写,没有。但是,假设您的类(class)做了这样的事情:
class X {
int * ptr;
public:
X() {
ptr = new int{0};
}
};
现在,您的代码会泄漏,因为每次创建 X
时,您都会有一个永远不会被删除的指针。
要解决这个问题,您需要确保 A) 析构函数正确清理指针,以及 B) 您的复制/移动构造函数/运算符是正确的。
class X {
int * ptr;
public:
X() {
ptr = new int{0};
}
X(int val) {
ptr = new int{val};
}
X(X const& x) : X() {
*ptr = *(x.ptr);
}
X(X && x) : X() {
std::swap(ptr, x.ptr);
}
X & operator=(X const& x) {
*ptr = *(x.ptr);
return *this;
}
X & operator=(X && x) {
std::swap(ptr, x.ptr);
return *this;
}
~X() noexcept {
delete ptr;
}
};
如果按原样在您的main
函数或我的函数中使用,此代码将不会泄漏内存。但是,当然,如果您这样做并不能阻止泄漏:
int main() {
X * ptr = new X{};
return 0;
//Whelp.
}
一般来说,如果您根本不需要使用指针,建议您改用 std::unique_ptr
之类的东西,因为它免费提供了大部分内容。
int main() {
std::unique_ptr<X> ptr{new X{}};
return 0;
//Destructor called on *ptr
//`delete` called on ptr
}
这在您的原始类(class)中是个好主意,但需要注意的是,除非您明确更改它,否则您的类(class)将不再可复制(尽管它仍然是可移动的):
class X {
std::unique_ptr<int> ptr;
public:
X() {
ptr.reset(new int{0});
}
X(int val) {
ptr.reset(new int{val});
}
//X(X && x); //auto generated by compiler
//X & operator=(X && x); //auto generated by compiler
//~X() noexcept; //auto generated by compiler
//X(X const& x); //Deleted by compiler
//X & operator=(X const& x); //Deleted by compiler
};
我们可以看到我以前版本的main
的变化:
int main() {
X a; //Default-Constructor
//X b = a; //Was Copy-Constructor, no longer compiles
X c(5); //Other Constructor
X d{7}; //Also Other Constructor
X f{}; //Default-Constructor
X g = X(8); //Other Constructor (uses copy-elision to avoid calling Other + move-assign + Destructor)
X h = std::move(c); //Move-Constructor (uses copy-elision to avoid calling Default + move-assign)
//b = c; //Was Copy-assignment, no longer compiles
c = std::move(d); //Move-assignment
d = X{15}; //Other Constructor, then Move-Assignment, then Destructor on `X{15}`.
return 0;
//Destructor on `h`
//Destructor on `g`
//Destructor on `f`
//Destructor on `d`
//Destructor on `c`
//Destructor on `a`
}
如果你想使用 std::unique_ptr
,但也希望生成的类是可复制的,你需要使用我讨论的技术自己实现复制构造函数。
应该就这些了!如果我遗漏了什么,请告诉我。
关于c++ - 如果将变量设置为新对象,旧对象会发生什么情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44707245/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!