I am a C++ programmer and recently joined a new company that uses a lot of C. When they reviewed my code, they were thinking I over-designed some of the things which I totally disagreed. The company is doing everything in embedded system, so my code needs to be memory efficient, but the stuff I am doing is not CPU intensive. I would like to know how you guys think what my design. Here is the list.
我是一名C ++程序员,最近加入了一家使用大量C的新公司。当他们审查我的代码时,他们认为我过度设计了一些我完全不同意的事情。该公司正在做嵌入式系统中的所有事情,因此我的代码需要内存效率,但我正在做的事情不是CPU密集型的。我想知道你们怎么想我的设计。这是清单。
-
I have some arrays that need to pass around and eventually need to pass to some C code. I could pass a pointer and a size all over of the place. But I chose to create a class that represents this -- a class that has a fixed size (we know the maximum size) buffer, and a length which should be always <= the size of the buffer, otherwise assert. In this way, I can pass the array around with only one variable instead of two, and if the maximum size changes in the future, I should be able to change it easily. I don't use dynamic allocation for the array because it is embedded system and memory allocation could potentially fail and we don't use exception. The class is probably less than 30 lines code, and I use it for quite a few places. They said I over-designed it.
我有一些需要传递的数组,最终需要传递给一些C代码。我可以传递一个指针和一个大小的地方。但是我选择创建一个表示这个的类 - 一个具有固定大小(我们知道最大大小)缓冲区的类,以及一个长度应始终<=缓冲区的大小,否则断言。通过这种方式,我可以只使用一个变量而不是两个变量传递数组,如果将来最大大小发生变化,我应该可以轻松地更改它。我不使用数组的动态分配,因为它是嵌入式系统和内存分配可能会失败,我们不使用异常。该类可能少于30行代码,我在很多地方使用它。他们说我过度设计了它。
-
They have their own containers implementation in C. I needed to use one of them, but I wanted to hide all the detailed code away from my main logic, so I created a wrapper class for it. The wrapper class is similar to stl, so I have iterators and it manages the memory allocation internally, but unlike stl, it returns a error code when it can't allocate more memory. Their argument on this one is that I am the only one uses it, so they don't want it to be in the repository. I found it stupid to be honest.
他们在C中有自己的容器实现。我需要使用其中一个,但我想隐藏所有详细的代码,远离我的主逻辑,所以我为它创建了一个包装类。包装类类似于stl,所以我有迭代器并且它在内部管理内存分配,但与stl不同,它在无法分配更多内存时返回错误代码。他们对这个问题的论点是我是唯一一个使用它的人,因此他们不希望它存在于存储库中。说实话,我发现这很愚蠢。
EDIT: The following class is more or less that I used for point 1. All I wanted to do is to have something to pass around without carrying the length all the time.
编辑:以下课程或多或少是我用于第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; }
};
7 个解决方案
#1
7
You're probably right, but on the other hand if everyone in the company decided that they don't like the existing APIs, and each designed their own shims and helper functions, that only they used, then maintenance would be tricky.
你可能是对的,但另一方面,如果公司中的每个人都认为他们不喜欢现有的API,并且每个人都设计了他们自己的垫片和辅助功能,只有他们使用,那么维护将是棘手的。
If your array wrapper is "over-designed", then I'd question whether the code reviewer considers any amount of design to be acceptable. It looks harmless to me[*]. I suppose you could have just made it a struct with two public members, and lose the benefit of read-onliness. How keen are your colleagues on const-correctness in general?
如果您的数组包装器“过度设计”,那么我会质疑代码审查者是否认为任何数量的设计都是可接受的。它看起来对我无害[*]。我想你可能只是让它成为一个有两个公共成员的结构,并失去了阅读的好处。你的同事对整体的正确性有多敏锐?
I think the goal for 2 should be to reach consensus on whether that C API should be used directly from C++, or wrapped. If it should be wrapped (and the arguments for that are probably quite strong, what with namespacing and RAII), design a wrapper that everyone will use, and designate it "the C++ API for this module" rather than "a C++ wrapper that one module uses for this other module".
我认为2的目标应该是就C API是直接使用C ++还是包装来达成共识。如果它应该被包装(并且其参数可能非常强大,使用命名空间和RAII),设计一个每个人都将使用的包装器,并将其指定为“此模块的C ++ API”而不是“C ++包装器”模块用于这个其他模块“。
It's possible that everyone else genuinely prefers the API as it is, over a more OO API or using STL. Following their conventions will make it easiest for them to maintain your code, as long as their conventions are solid C programming style. C++ is a multi-paradigm language, and "C with a limited number of bells and whistles" isn't the paradigm you're used to. But it is a valid paradigm, and if it's what the existing codebase uses then you have to question whether what your company needs right now is a one-man revolution, however enlightened.
其他人可能真的更喜欢API,通过更多的OO API或使用STL。遵循他们的约定将使他们最容易维护您的代码,只要他们的约定是坚实的C编程风格。 C ++是一种多范式语言,“具有有限数量的花里胡哨的C”并不是您习惯的范例。但它是一个有效的范例,如果它是现有代码库使用的那么你必须质疑你的公司现在需要的是一个单人革命,无论多么开明。
[*] (the API, that is. They might question whether it will be passed by value inappropriately, and whether it's wise for every instance to have to be as big as the biggest. That's all for you to argue out with the reviewer, but is nothing to do with "over-design".
[*](API,也就是说。他们可能会质疑它是否会被价值不合理地传递,以及每个实例是否必须像最大的那样大。这就是你要与审稿人争论的全部内容,但与“过度设计”无关。
#2
8
First things first: You joined a new company, so you can expect that you need to learn to play by their rules. You're still "the new guy" and there will be some resistance to "your way" of doing things, even if it is better. Get used to them and slowly integrate yourself and your ideas.
首先要做的事情是:你加入了一家新公司,所以你可以期望你需要学会遵守他们的规则。你仍然是“新人”,即使它更好,也会对你的“做事方式”有所抵抗。习惯他们,慢慢融入自己和你的想法。
As to #1, passing a pointer+size is certainly a pain for the programmer, but it's the most memory-efficient way of doing things. Your class is not "over"-designed, but what happens if MAXSIZE becomes really large at some point in the future? All of your instances will take that much space each, even when they don't need to. You could wind up running out of space simply because the MAXSIZE changed, even if nothing needed that much space.
至于#1,传递指针+大小对程序员来说无疑是一种痛苦,但它是最节省内存的方式。你的课程没有“过度”设计,但如果MAXSIZE在未来的某个时刻变得非常大,会发生什么?你的所有实例都会占用那么多空间,即使它们不需要。你最终可能会因为MAXSIZE改变而耗尽空间,即使没有什么需要这么大的空间。
As to #2, it's a tossup on whether it's an unnecessary layer (perhaps it would be better suited to improve their wrapper instead of simply wrapping it again?), but this will come down to how well you integrate with them and make suggestions.
对于#2来说,它是否是一个不必要的层(或许它更适合改进它们的包装而不是简单地再包装它?),但是这将归结为你如何与它们集成并提出建议。
In summary, I wouldn't call it "overdesigned", but in an embedded situation you need to be very wary of generalizing code to save yourself effort vs saving memory..
总而言之,我不会称之为“过度设计”,但在嵌入式情况下,您需要非常警惕通用代码以节省自己的努力与节省内存。
#3
3
A c++ wrapper for the already existing c-style container-library is a nice thing to have. But make sure it's really a wrapper, not a wrapper with bolted on bells and whistles.
已经存在的c风格容器库的c ++包装器是一件好事。但要确保它真的是一个包装纸,而不是用铃铛和口哨闩上的包装纸。
If you declare all your access functions as inline and write your wrapper using the leanest possible implementation there should be exactly zero overhead in code and data-size.
如果您将所有访问函数声明为内联并使用最可能的实现编写包装器,则代码和数据大小应该只有零开销。
Such a wrapper will just give you a class-like interface to the c-library, and that's good practice for a C/C++ project.
这样的包装器只会给你一个类c-library的类接口,这是C / C ++项目的好习惯。
I suggest to check your code. Take a look at the disassembly of a little test-case using your wrapper and compare it to a c-only implementation. If you see any additional complexity, allocations or calls to your class implementation you have overhead and maybe overengineered a bit.
我建议检查你的代码。使用您的包装器查看一个小测试用例的反汇编,并将其与仅限c的实现进行比较。如果你看到任何额外的复杂性,分配或调用你的类实现,你有开销,可能过度工程。
Proving that your wrapper generates more or less identical code compared to the c-version may convince the other programmers that a wrapper here and there does no harm. It follows the way C++ programs are written and will result in a cleaner and more consistent code-base.
与c版本相比,证明你的包装器生成或多或少相同的代码可能会让其他程序员相信这里的包装器没有任何损害。它遵循C ++程序的编写方式,将产生更清晰,更一致的代码库。
Btw - The "we don't want no useless wrapper-class in our repository" thing is a social problem, not a technical one. You're the new guy. If I would be in your position I would play by their rules for a couple of month and - after I've proven myself - introduce them to your ideas.
顺便说一句 - “我们不希望在我们的存储库中没有无用的包装器”,这是一个社会问题,而不是技术问题。你是新人。如果我在你的位置,我会按照他们的规则玩几个月 - 在我证明了自己之后 - 向他们介绍你的想法。
#4
2
On the one hand, if you're comfortable with C++ and they use C, then helper classes are probably a good thing, for you at least. On the other hand, if you're writing any sort of container class, you're almost certainly better off using STL directly and writing a helper function to bridge the gap between your STL container and the C code. Don't reinvent the wheel.
一方面,如果你对C ++感到满意并且他们使用C,那么至少对你来说辅助类可能是一件好事。另一方面,如果你正在编写任何类型的容器类,你几乎肯定最好直接使用STL并编写一个辅助函数来弥合STL容器和C代码之间的差距。不要重新发明*。
#5
2
"Over designed" is very relative. The C-guys in your group probably see a problem with your class because when you pass your class by reference, you're going to make a copy of that entire array. That'll can a fair amount of time on an "embedded" system (depending on your definition of embedded) Of course, if you pass by address, this isn't a problem.
“过度设计”非常相对。你小组中的C-man可能会看到你的课有问题,因为当你通过引用传递你的类时,你将要复制整个数组。这对于“嵌入式”系统来说可能需要相当长的时间(取决于您对嵌入式系统的定义)当然,如果您通过地址传递,这不是问题。
Your #2 is a cultural issue. If they're not willing to try new programming techniques, then you're going to be viewed as an outsider. That's something you don't want to happen. Introduce them slowly.
你的#2是一个文化问题。如果他们不愿意尝试新的编程技术,那么你将被视为局外人。这是你不想发生的事情。慢慢介绍它们。
As for not putting it in the repository - that's bullshit. Everyone should put everything in the repository so that people can access it and find bugs later.
至于不把它放在存储库中 - 这就是废话。每个人都应该将所有内容放在存储库中,以便人们可以访问它并稍后查找错误。
Not to toot my own horn, but I asked a related question just a few days ago: Using C++ in an embedded environment
不要自言自语,但几天前我问了一个相关的问题:在嵌入式环境中使用C ++
#6
1
I am unsure about 1. Maybe you could give a simple code example to illustrate.
我不确定1.也许您可以举一个简单的代码示例来说明。
As for 2, I agree with you. As a hardened C programmer who's trying to get up-to-speed on C++, I am totally sold by the idea of writing thin facades around existing C APIs, for ease of error-handling and resource management.
至于2,我同意你的看法。作为一名努力学习C ++的强化C程序员,我完全被在现有C API上编写薄外观的想法所淹没,以便于错误处理和资源管理。
#7
1
You make a copy of the data for your class, which no longer qualifies your class as being a mere wrapper class. Although this will protect you from the data getting deleted out from under you, if the original data was modified, your data would be out of date.
您为类创建了数据的副本,这些数据不再将您的类限定为仅仅是包装类。虽然这可以保护您免受从您下面删除的数据的影响,但如果原始数据被修改,您的数据将会过时。
The idea of encapsulating the array with the size is reasonable. Perhaps you can get them to buy into adding the size field to their container, assuming it's not just a const int*. But I can see that for the mere privilege of encapsulating the size, the overhead of extra memory and runtime to model and initialize the class may seem unpalatable for them.
用大小封装数组的想法是合理的。也许你可以让他们购买将size字段添加到他们的容器中,假设它不仅仅是一个const int *。但是我可以看到,仅仅为了封装大小的特权,额外内存和运行时的开销来建模和初始化类似乎对他们来说是不合适的。
Beyond that, I have to sympathize completely as far as dealing with the classic C-bias, which is that C++ is evil and slow. Flashbacks...shudder.
除此之外,我必须完全同情处理经典的C偏见,即C ++是邪恶而缓慢的。闪回......不寒而栗。
#1
7
You're probably right, but on the other hand if everyone in the company decided that they don't like the existing APIs, and each designed their own shims and helper functions, that only they used, then maintenance would be tricky.
你可能是对的,但另一方面,如果公司中的每个人都认为他们不喜欢现有的API,并且每个人都设计了他们自己的垫片和辅助功能,只有他们使用,那么维护将是棘手的。
If your array wrapper is "over-designed", then I'd question whether the code reviewer considers any amount of design to be acceptable. It looks harmless to me[*]. I suppose you could have just made it a struct with two public members, and lose the benefit of read-onliness. How keen are your colleagues on const-correctness in general?
如果您的数组包装器“过度设计”,那么我会质疑代码审查者是否认为任何数量的设计都是可接受的。它看起来对我无害[*]。我想你可能只是让它成为一个有两个公共成员的结构,并失去了阅读的好处。你的同事对整体的正确性有多敏锐?
I think the goal for 2 should be to reach consensus on whether that C API should be used directly from C++, or wrapped. If it should be wrapped (and the arguments for that are probably quite strong, what with namespacing and RAII), design a wrapper that everyone will use, and designate it "the C++ API for this module" rather than "a C++ wrapper that one module uses for this other module".
我认为2的目标应该是就C API是直接使用C ++还是包装来达成共识。如果它应该被包装(并且其参数可能非常强大,使用命名空间和RAII),设计一个每个人都将使用的包装器,并将其指定为“此模块的C ++ API”而不是“C ++包装器”模块用于这个其他模块“。
It's possible that everyone else genuinely prefers the API as it is, over a more OO API or using STL. Following their conventions will make it easiest for them to maintain your code, as long as their conventions are solid C programming style. C++ is a multi-paradigm language, and "C with a limited number of bells and whistles" isn't the paradigm you're used to. But it is a valid paradigm, and if it's what the existing codebase uses then you have to question whether what your company needs right now is a one-man revolution, however enlightened.
其他人可能真的更喜欢API,通过更多的OO API或使用STL。遵循他们的约定将使他们最容易维护您的代码,只要他们的约定是坚实的C编程风格。 C ++是一种多范式语言,“具有有限数量的花里胡哨的C”并不是您习惯的范例。但它是一个有效的范例,如果它是现有代码库使用的那么你必须质疑你的公司现在需要的是一个单人革命,无论多么开明。
[*] (the API, that is. They might question whether it will be passed by value inappropriately, and whether it's wise for every instance to have to be as big as the biggest. That's all for you to argue out with the reviewer, but is nothing to do with "over-design".
[*](API,也就是说。他们可能会质疑它是否会被价值不合理地传递,以及每个实例是否必须像最大的那样大。这就是你要与审稿人争论的全部内容,但与“过度设计”无关。
#2
8
First things first: You joined a new company, so you can expect that you need to learn to play by their rules. You're still "the new guy" and there will be some resistance to "your way" of doing things, even if it is better. Get used to them and slowly integrate yourself and your ideas.
首先要做的事情是:你加入了一家新公司,所以你可以期望你需要学会遵守他们的规则。你仍然是“新人”,即使它更好,也会对你的“做事方式”有所抵抗。习惯他们,慢慢融入自己和你的想法。
As to #1, passing a pointer+size is certainly a pain for the programmer, but it's the most memory-efficient way of doing things. Your class is not "over"-designed, but what happens if MAXSIZE becomes really large at some point in the future? All of your instances will take that much space each, even when they don't need to. You could wind up running out of space simply because the MAXSIZE changed, even if nothing needed that much space.
至于#1,传递指针+大小对程序员来说无疑是一种痛苦,但它是最节省内存的方式。你的课程没有“过度”设计,但如果MAXSIZE在未来的某个时刻变得非常大,会发生什么?你的所有实例都会占用那么多空间,即使它们不需要。你最终可能会因为MAXSIZE改变而耗尽空间,即使没有什么需要这么大的空间。
As to #2, it's a tossup on whether it's an unnecessary layer (perhaps it would be better suited to improve their wrapper instead of simply wrapping it again?), but this will come down to how well you integrate with them and make suggestions.
对于#2来说,它是否是一个不必要的层(或许它更适合改进它们的包装而不是简单地再包装它?),但是这将归结为你如何与它们集成并提出建议。
In summary, I wouldn't call it "overdesigned", but in an embedded situation you need to be very wary of generalizing code to save yourself effort vs saving memory..
总而言之,我不会称之为“过度设计”,但在嵌入式情况下,您需要非常警惕通用代码以节省自己的努力与节省内存。
#3
3
A c++ wrapper for the already existing c-style container-library is a nice thing to have. But make sure it's really a wrapper, not a wrapper with bolted on bells and whistles.
已经存在的c风格容器库的c ++包装器是一件好事。但要确保它真的是一个包装纸,而不是用铃铛和口哨闩上的包装纸。
If you declare all your access functions as inline and write your wrapper using the leanest possible implementation there should be exactly zero overhead in code and data-size.
如果您将所有访问函数声明为内联并使用最可能的实现编写包装器,则代码和数据大小应该只有零开销。
Such a wrapper will just give you a class-like interface to the c-library, and that's good practice for a C/C++ project.
这样的包装器只会给你一个类c-library的类接口,这是C / C ++项目的好习惯。
I suggest to check your code. Take a look at the disassembly of a little test-case using your wrapper and compare it to a c-only implementation. If you see any additional complexity, allocations or calls to your class implementation you have overhead and maybe overengineered a bit.
我建议检查你的代码。使用您的包装器查看一个小测试用例的反汇编,并将其与仅限c的实现进行比较。如果你看到任何额外的复杂性,分配或调用你的类实现,你有开销,可能过度工程。
Proving that your wrapper generates more or less identical code compared to the c-version may convince the other programmers that a wrapper here and there does no harm. It follows the way C++ programs are written and will result in a cleaner and more consistent code-base.
与c版本相比,证明你的包装器生成或多或少相同的代码可能会让其他程序员相信这里的包装器没有任何损害。它遵循C ++程序的编写方式,将产生更清晰,更一致的代码库。
Btw - The "we don't want no useless wrapper-class in our repository" thing is a social problem, not a technical one. You're the new guy. If I would be in your position I would play by their rules for a couple of month and - after I've proven myself - introduce them to your ideas.
顺便说一句 - “我们不希望在我们的存储库中没有无用的包装器”,这是一个社会问题,而不是技术问题。你是新人。如果我在你的位置,我会按照他们的规则玩几个月 - 在我证明了自己之后 - 向他们介绍你的想法。
#4
2
On the one hand, if you're comfortable with C++ and they use C, then helper classes are probably a good thing, for you at least. On the other hand, if you're writing any sort of container class, you're almost certainly better off using STL directly and writing a helper function to bridge the gap between your STL container and the C code. Don't reinvent the wheel.
一方面,如果你对C ++感到满意并且他们使用C,那么至少对你来说辅助类可能是一件好事。另一方面,如果你正在编写任何类型的容器类,你几乎肯定最好直接使用STL并编写一个辅助函数来弥合STL容器和C代码之间的差距。不要重新发明*。
#5
2
"Over designed" is very relative. The C-guys in your group probably see a problem with your class because when you pass your class by reference, you're going to make a copy of that entire array. That'll can a fair amount of time on an "embedded" system (depending on your definition of embedded) Of course, if you pass by address, this isn't a problem.
“过度设计”非常相对。你小组中的C-man可能会看到你的课有问题,因为当你通过引用传递你的类时,你将要复制整个数组。这对于“嵌入式”系统来说可能需要相当长的时间(取决于您对嵌入式系统的定义)当然,如果您通过地址传递,这不是问题。
Your #2 is a cultural issue. If they're not willing to try new programming techniques, then you're going to be viewed as an outsider. That's something you don't want to happen. Introduce them slowly.
你的#2是一个文化问题。如果他们不愿意尝试新的编程技术,那么你将被视为局外人。这是你不想发生的事情。慢慢介绍它们。
As for not putting it in the repository - that's bullshit. Everyone should put everything in the repository so that people can access it and find bugs later.
至于不把它放在存储库中 - 这就是废话。每个人都应该将所有内容放在存储库中,以便人们可以访问它并稍后查找错误。
Not to toot my own horn, but I asked a related question just a few days ago: Using C++ in an embedded environment
不要自言自语,但几天前我问了一个相关的问题:在嵌入式环境中使用C ++
#6
1
I am unsure about 1. Maybe you could give a simple code example to illustrate.
我不确定1.也许您可以举一个简单的代码示例来说明。
As for 2, I agree with you. As a hardened C programmer who's trying to get up-to-speed on C++, I am totally sold by the idea of writing thin facades around existing C APIs, for ease of error-handling and resource management.
至于2,我同意你的看法。作为一名努力学习C ++的强化C程序员,我完全被在现有C API上编写薄外观的想法所淹没,以便于错误处理和资源管理。
#7
1
You make a copy of the data for your class, which no longer qualifies your class as being a mere wrapper class. Although this will protect you from the data getting deleted out from under you, if the original data was modified, your data would be out of date.
您为类创建了数据的副本,这些数据不再将您的类限定为仅仅是包装类。虽然这可以保护您免受从您下面删除的数据的影响,但如果原始数据被修改,您的数据将会过时。
The idea of encapsulating the array with the size is reasonable. Perhaps you can get them to buy into adding the size field to their container, assuming it's not just a const int*. But I can see that for the mere privilege of encapsulating the size, the overhead of extra memory and runtime to model and initialize the class may seem unpalatable for them.
用大小封装数组的想法是合理的。也许你可以让他们购买将size字段添加到他们的容器中,假设它不仅仅是一个const int *。但是我可以看到,仅仅为了封装大小的特权,额外内存和运行时的开销来建模和初始化类似乎对他们来说是不合适的。
Beyond that, I have to sympathize completely as far as dealing with the classic C-bias, which is that C++ is evil and slow. Flashbacks...shudder.
除此之外,我必须完全同情处理经典的C偏见,即C ++是邪恶而缓慢的。闪回......不寒而栗。