c++ - 这是动态内存分配的好做法还是坏做法?
问题描述
我见过其他人使用它,它看起来非常聪明,但我不确定这是好还是坏的做法。它可以工作,而且我个人喜欢它的工作方式,但是在更大的程序范围内这样做真的有用吗?
他们所做的是在实际函数参数中动态分配一些数据类型,并在函数中删除它。这是一个例子:
#include <iostream>
class Foo {
private:
int number;
public:
Foo(int n) : number(n) { }
int num() { return number; }
Foo* new_num (int i) { number = i; }
};
void some_func (int thing, Foo* foo);
int main() {
std::cout << "Enter number: ";
int n;
std::cin >> n;
some_func(n, new Foo(0)); // <-- uses the 'new' operator with a function argument
return 0;
}
// calculates difference between 'thing' and 'n'
// then puts it inside the Foo object
void some_func (int thing, Foo* foo) {
std::cout << "Enter another number: ";
int n;
std::cin >> n;
std::cout << "Difference equals " << foo->new_num(thing - n)->num() << std::endl;
delete foo; // <-- the Foo object is deleted here
}
我知道可以在函数参数中使用运算符,但我只知道使用级别 2、4 到 15 和 17 的运算符以及赋值运算符 、? :
和++
、--
一元+
和-
、!
、~
、*
和&
,sizeof
和强制转换。像这样的东西:
foo((x < 3)? 5 : 6, --y * 7);
bar(player->weapon().decr_durability().charge(0.1), &shield_layers);
所以,我实际上有两个问题。
new
-as-an-argument 是好的做法吗?由于显然任何返回类型的运算符都有效,如果
new
有效,正在使用这些良好做法吗?::
,new []
,throw
,sizeof...
,typeid
,noexcept
,alignof
解决方案
不,这一点都不聪明。它采用了一个更简单、更通用的函数,并无缘无故地降低了它的功能,同时为难以调试的错误创建了程序的入口点。
我不清楚究竟Foo::new_num
是什么意思(现在它不能编译),所以我不会直接解决你的例子,但考虑以下两个代码示例:
void bad_function(int i, F * f)
{
f->doSomething(i);
delete f;
}
// ...
bad_function(0, new F(1, 2, 3));
相对
void good_function(int i, F & f)
{
f.doSomething(i);
}
// ...
good_function(0, F(1, 2, 3));
在这两种情况下,您都分配了一个新的 F 对象作为方法调用的一部分,并且一旦使用完它就会被销毁,因此使用bad_function
而不是good function
. 但是,您可以做很多good_function
不那么容易做的事情bad_function
,例如
void multi_function(const std::vector<int> & v, F & f)
{
for(int i : v) { good_function(i, f); }
}
使用该good_function
版本意味着语言本身也会阻止您做各种您不想做的事情,例如
F * f; // never initialized
bad_function(0, f); // undefined behavior, resulting in a segfault if you're lucky
它也是更好的软件工程,因为它使人们更容易从它的签名中猜测你的函数做了什么。如果我调用一个函数,其目的涉及从控制台读取一个数字并进行算术运算,我绝对不希望它删除我传入的参数,并且在我花了半个小时找出导致一些不相关的一些模糊崩溃的原因之后我会对编写该函数的人感到愤怒。
顺便说一句,假设F::doSomething
不会F
以任何方式改变当前实例的值,它应该被声明const
:
class F
{
void doSomething(int i) const;
// ...
};
并且good_function
还应该接受一个const
论点:
void good_function(int i, const F & f);
这让任何查看签名的人都可以自信地推断出该函数不会做任何愚蠢的事情,比如弄乱f
传递给函数的值,因为编译器会阻止它。这反过来又让他们更快地编写代码,因为这意味着少了一件需要担心的事情。
事实上,如果我看到一个带有bad_function
's 之类签名的函数并且没有明显的原因,那么我会立即担心它会做一些我不想要的事情,我可能会在使用之前阅读该函数它。
推荐阅读
- google-analytics - How to implement the Google Analytics event monitoring on a website if the standard Analytics tracking code seems not to be enough?
- android - 限制 IPackageInstallObserver 和 IPackageDeleteObserver 上的目标 API 28
- php - 无法为移动和网络平台设置操作
- android - 在 RecyclerView 适配器中使用 Glide 加载的 Gif 无法正常播放
- mysql - 我可以获得有关如何使用以下标签加入我的表的帮助吗?
- html - 它是 Chrome 中 em DIV 的秘密最小尺寸(宽度/高度)吗?
- javascript - 具有未知长度的数据结构
- aws-amplify - Schema @connection to a special field
- mvvm - How to consume data from url in application
- javascript - Antd Table:如何用列表中的对象渲染表格