我是一名C ++程序员,最近加入了一家使用大量C的新公司。当他们审查我的代码时,他们认为我过度设计了一些我完全不同意的事情。该公司正在做嵌入式系统中的所有事情,因此我的代码需要是内存
高效,但我正在做的事情不是CPU密集型的。我想知道你们怎么想我的设计。这是清单。
我有一些需要传递的数组,最终需要传递给某些C代码。我可以在这个地方传递一个指针和一个大小。但是我选择创建一个表示它的类 - 一个具有固定大小(我们知道最大大小)缓冲区的类,以及一个长度应始终< =缓冲区的大小,否则断言。通过这种方式,我可以只使用一个变量而不是两个变量来传递数组,如果将来最大的大小发生变化,我应该可以轻松地更改它。我没有为数组使用动态分配,因为它是嵌入式系统和内存分配可能会失败,我们不使用异常。该类可能少于30行代码,我在很多地方使用它。他们说我过度设计了它。
他们在C中有自己的容器实现。我需要使用其中一个,但我想隐藏所有详细的代码,远离我的主逻辑,所以我创建了一个包装类 为了它。包装类类似于stl,所以我有迭代器并且它管理内存 内部分配,但与stl不同,它在无法分配更多内容时返回错误代码 记忆。他们对这个问题的论点是我是唯一一个使用它的人,因此他们不希望它存在于存储库中。说实话,我发现这很愚蠢。
编辑:以下课程或多或少是我用于第1点的课程。我想要做的就是在没有长度的情况下传递一些东西。
class A
{
static const MAX_SIZE = 20;
int m_Array[MAX_SIZE];
size_t m_Len;
public:
A(const int* array, size_t len)
{
assert(len <= MAX_SIZE);
memcpy(m_Array, array, len);
m_Len = len;
}
size_t GetLen() const { return m_Len; }
const int* GetArray() const { return m_Array; }
};
答案 0 :(得分:8)
首先要做的事情是:你加入了一家新公司,所以你可以期望你需要学会遵守他们的规则。你仍然是“新人”,即使它更好,也会对你的“做事方式”产生一些阻力。习惯他们,慢慢融入自己和你的想法。
对于#1,传递一个指针+大小对程序员来说无疑是一种痛苦,但它是最节省内存的方式。你的课程没有“过度”设计,但如果MAXSIZE在未来的某个时刻变得非常大,会发生什么?你的所有实例都会占用那么多空间,即使它们不需要。你可能会因为MAXSIZE改变而耗尽空间,即使没有什么需要这么大的空间。
至于#2,它是否是一个不必要的层(或许它更适合改进它们的包装而不是简单地再包装它?),但是这将归结为你与它们的整合程度如何?提出建议。
总之,我不会称之为“过度设计”,但在嵌入式情况下,您需要非常谨慎地推广代码以节省自己的努力以节省内存..
答案 1 :(得分:7)
你可能是对的,但另一方面,如果公司中的每个人都认为他们不喜欢现有的API,并且每个人都设计了自己的垫片和辅助功能,只有他们使用过,那么维护就会很棘手
如果您的数组包装器“过度设计”,那么我会质疑代码审核者是否认为任何的设计数量是可以接受的。它看起来对我无害[*]。我想你可能只是让它成为一个有两个公共成员的结构,并失去了阅读的好处。你的同事对整体的正确性有多敏锐?
我认为2的目标应该是就C API是直接使用C ++还是包装来达成共识。如果它应该被包装(并且其参数可能非常强大,使用命名空间和RAII),设计一个每个人都将使用的包装器,并将其指定为“此模块的C ++ API”而不是“C ++包装器”模块用于这个其他模块“。
其他所有人都可能通过更多的OO API或使用STL来真正优先选择API。遵循他们的约定将使他们最容易维护您的代码,只要他们的约定是坚实的C编程风格。 C ++是一种多范式语言,“具有有限数量的花里胡哨的C”并不是您习惯的范例。但这是一个有效的范例,如果它是现有代码库所使用的,那么你必须质疑你的公司现在需要的是一个单人革命,无论多么开明。
[*](API,也就是说。他们可能会质疑它是否会以不合适的价值传递,以及每个实例是否必须与最大的实例一样大。这就是你要争论的全部内容。审稿人,但与“过度设计”无关。
答案 2 :(得分:3)
现有的c风格容器库的c ++包装器是一件好事。但要确保它真的是一个包装纸,而不是一个用铃铛和口哨闩上的包装纸。
如果您将所有访问函数声明为内联并使用最可能的实现编写包装器,那么代码和数据大小应该只有零开销。
这样的包装器只会为你提供一个类c-library的类接口,这是C / C ++项目的好习惯。
我建议检查一下你的代码。使用您的包装器查看一个小测试用例的反汇编,并将其与仅限c的实现进行比较。如果你看到任何额外的复杂性,分配或调用你的类实现,你有开销,可能过度工程。
与c-version相比,证明你的包装器生成了或多或少相同的代码可能会让其他程序员相信这里的包装器并没有什么坏处。它遵循C ++程序的编写方式,将产生更清晰,更一致的代码库。
顺便说一句 - “我们不希望我们的存储库中没有无用的包装器”,这是一个社会问题,而不是技术问题。你是新人。如果我能够在你的位置上,我会按照他们的规则玩几个月 - 在我证明了自己之后 - 将它们介绍给你的想法。
答案 3 :(得分:2)
一方面,如果你对C ++感到满意并且他们使用C,那么帮助类对你来说可能是一件好事,至少对你而言。另一方面,如果你正在编写任何类型的容器类,你几乎肯定最好直接使用STL并编写一个帮助器函数来弥合STL容器和C代码之间的差距。 。不要重新发明轮子。
答案 4 :(得分:2)
“过度设计”是非常相对的。你小组中的C-man可能会看到你班上的问题,因为当你通过引用传递你的类时,你将要复制整个数组。这对于“嵌入式”系统来说可能需要相当长的时间(取决于您对嵌入式系统的定义)当然,如果您通过地址传递,这不是问题。
你的#2是一个文化问题。如果他们不愿意尝试新的编程技术,那么你将被视为局外人。这是你不想发生的事情。慢慢介绍它们。
至于不把它放在存储库中 - 这就是废话。每个人都应该将所有内容放在存储库中,以便人们可以访问它并稍后查找错误。
不要自言自语,但几天前我问了一个相关的问题: Using C++ in an embedded environment
答案 5 :(得分:1)
我不确定1.也许您可以举一个简单的代码示例来说明。
至于2,我同意你的看法。作为一名努力学习C ++的强化C程序员,我完全被在现有C API上编写薄外观的想法所淹没,以便于错误处理和资源管理。
答案 6 :(得分:1)
您为您的班级复制了数据,这不再使您的班级成为纯粹的包装类。虽然这可以保护您免受从您下面删除的数据的影响,但如果原始数据被修改,您的数据将会过时。
用大小封装数组的想法是合理的。也许你可以让他们购买将size字段添加到他们的容器中,假设它不仅仅是一个const int *。 但是我可以看到,仅仅为了封装大小的特权,额外内存和运行时的开销来模拟和初始化类似乎对他们来说是不合适的。
除此之外,我必须完全同情处理经典的C偏见,即C ++是邪恶而缓慢的。倒叙...颤动。