首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >手动内存分配和纯度

手动内存分配和纯度
EN

Software Engineering用户
提问于 2012-04-09 03:32:12
回答 4查看 1.4K关注 0票数 6

像Haskell这样的语言有纯洁的概念。在纯函数中,我不能在全局范围内变异任何状态。无论如何,Haskell完全抽象内存管理,因此内存分配在这里不是一个问题。

但是,如果语言可以像C++那样直接处理内存,那么它对我来说是非常模糊的。在这些语言中,内存分配会导致可见的变异。但如果我把创造新事物当作不洁的行为,实际上,几乎没有什么东西是纯洁的。所以纯洁的概念几乎毫无用处。

我应该如何处理语言中的纯度--将内存作为可见的全局对象?

EN

回答 4

Software Engineering用户

发布于 2012-04-09 04:24:53

我不得不不同意这个基本的前提。

C++ (使用您的例子,尽管同样适用于C、Pascal、Ada等)不会给堆带来任何真正的可见性。您可以尝试分配一些内存,这些内存可能成功或失败--但您无法了解分配成功或失败的原因,也无法了解其他分配可能导致成功/失败的原因。

换句话说,在一个地方分配一些内存不会产生其他任何地方都能直接看到的效果。是的,一种分配可能会导致另一种分配的失败,但是在可移植C++中的注释可以将它们组合在一起,2)即使是不可移植的方式,通常也几乎不可能实现这种连接。

另一方面,在Haskell (或任何其他语言)中,任何东西都不能改变所涉及的基础。试图分配比可用内存更多的内存(即使是虚拟地址空间)将失败,而不管是哪种语言。如果用户运行另一个占用所有内存的程序,那么C++或Haskell (或其他任何东西)都不能对此做很多事情,因此在一次运行中成功的分配可能会在另一次运行中失败。

公平地说,我想我应该补充一点,即使它不是可移植的,很多(大多数?)堆管理器包括额外的函数来遍历当前的堆,查看分配了哪些块等等。是的,我认为这样的事情可以被看作是破坏了“纯度”,但我的猜测是,包括在软件中使用堆的人可能不会为此而烦恼(而那些真正关心纯度的人只是不使用这种能力。

票数 1
EN

Software Engineering用户

发布于 2012-05-09 06:52:14

纯粹是一个概念,它不会因为编程语言没有强制执行而变得毫无用处。Haskell很可能是你最好的选择,如果你在寻找绝对的纯度保证,但这并不意味着这个概念在C++中是无用的。您当然可以提高C++中代码的纯度,这肯定会对其质量产生积极的影响。

票数 1
EN

Software Engineering用户

发布于 2012-04-09 04:50:29

我认为,当你说“制造新物体”是不纯的意味着几乎没有任何东西是纯洁的时,你就断言得太多了。如果您将内存分配与主线逻辑隔离开来,那么主线逻辑就可以按照情况的要求以“纯”或“不纯”的形式出现。我经常使用的一种技术是定义数据操作函数,这些函数使this对象保持不变,但这些函数为应该放置结果的目的地接受一个参数。(通常,我允许目标与this对象相同。)例如,

代码语言:javascript
复制
class Countdown
{
private:
    int _CountLeft;
public:
    void init(int CountLeft) { this->_CountLeft = CountLeft; }
    int getCountLeft() const { return this->_CountLeft; }
    bool decrease(Countdown &Dest) const {
        Dest._CountLeft = this->_CountLeft - 1;
        return Dest._CountLeft > 0;
    }
};

我知道这不是惯用的C++ (更详细地介绍一下),但它是在C++中实现纯函数的一种方式。

现在,我将尝试解释这个类的一些奇怪特性:

为什么使用init方法而不是构造函数?

我有意从该对象的规范中删除任何内存管理问题;使用构造函数或析构函数引入了类的行为对内存分配/释放的某些功能依赖。

这个函数如何“纯”?

“纯”的意思是,如果我们总是将对象的新实例作为目标参数,那么任何操作的输入数据都不会改变。例如:

代码语言:javascript
复制
Countdown CountdownArray[10];
CountdownArray[0].init(5);
for(
  int Index = 0;
  Index < 10 - 1 &&
    CountdownArray[Index].decrease(CountdownArray[Index+1];
  Index++)
{
    continue;
}

显然,这种行为并不是“纯的”,但是CountdownArray的元素从第一次初始化开始就没有被修改过;当给定适当的目标参数时,decrease方法确实是以纯方式运行的。

如何有效地管理这个类的内存?

在这种情况下,类的编写使得Dest参数可以是this指向的相同对象:

代码语言:javascript
复制
Countdown CD;
CD.init(5);
while(CD.decrase(CD))
{
}

这显然降低了行为的“纯”性,但也使生成的代码显着地提高了内存效率。

这种技术是如何与继承交互的?

问得好。在使用此技术时,我避免继承。

结论

一台通用计算机实际上不可能是“纯的”--我们在计算机中有有限的资源可供使用(内存、磁盘空间、CPU寄存器),有效地使用这些资源需要它们是可变的。人们在计算中所说的“纯洁”的意思是,我们已经将不可变的和可变的分离开来,而不变的状态可以被认为是“纯的”。您是正确的,内存分配可能会对系统的其他部分产生副作用(例如,在内存耗尽时导致以后的分配失败)。但是,从我们想要纯净的代码中提取内存分配可能是切实可行的。

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/143558

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档