The code listed below is intended to calculate some rotation data which will later get used in my rendering code.
renderer.cpp:
rendered_image renderer::common_tasks(render_info const& info) {
//info.radius is a float, info.min_image_size is an int calculated by taking the minimum
//of info.image_width and info.image_height
cl_float raw_delta = 2.f * info.radius / info.min_image_size;
//cl_float4 is functionally a wrapper around float[4].
//info.rotation is a float value representing the rotation in degrees
cl_float4 final_deltas{
cos(to_radians(info.rotation)) * raw_delta,
sin(to_radians(info.rotation)) * raw_delta,
-sin(to_radians(info.rotation)) * raw_delta,
cos(to_radians(info.rotation)) * raw_delta
};
//Other, irrelevant code
/*...*/
}
But of course, I wanted to clean up the code a bit, so I rewrote it like this:
renderer.cpp:
cl_float4 get_deltas(render_info const& info) {
//info.radius is a float, info.min_image_size is an int calculated by taking the minimum
//of info.image_width and info.image_height
cl_float raw_delta = 2.f * info.radius / info.min_image_size;
//cl_float4 is functionally a wrapper around float[4].
//info.rotation is a float value representing the rotation in degrees
cl_float4 final_deltas{
cos(to_radians(info.rotation)) * raw_delta,
sin(to_radians(info.rotation)) * raw_delta,
-sin(to_radians(info.rotation)) * raw_delta,
cos(to_radians(info.rotation)) * raw_delta
};
return final_deltas;
}
rendered_image renderer::common_tasks(render_info const& info) {
cl_float4 final_deltas = get_deltas(info);
//Other, irrelevant code
/*...*/
}
Now, however, I have a globally declared function get_deltas
that only exists in this .cpp file. As-is, this code compiles and runs normally, but are there any significant risks to me writing code like this? Should I be nesting the function in a namespace or declare it private in the renderer
class? I know for a fact that I will never need to use get_deltas
anywhere else in my code: does that change whether this is a good or bad use of this code style?
3 Answers 3
As a matter of principle private or local methods should always either be private
members of the class or static
local functions. Declaring a function as static it becomes file scope and the linker will throw an error if it is attempted to be used outside of the scope of the file that it is declared in.
You can also use the anonymous namespace to achieve the same thing which is more verbose but some places prefer.
One of the major reasons is that, while you may never intend to use get_deltas
elsewhere someone else might at sometime in the life of the program, possibly as a typo, and then there is a reasonable chance that the program will compile and link without errors, (you should get a warning), but will have an obscure and hard to locate bug.
-
1I went with the anonymous Namespace for my code. All of this was good information though.Xirema– Xirema2017年02月14日 17:39:44 +00:00Commented Feb 14, 2017 at 17:39
-
It's only more verbose if you only have the one function in it.Pete Kirkham– Pete Kirkham2017年04月21日 14:14:11 +00:00Commented Apr 21, 2017 at 14:14
In addition to Steve Barnes answer:
- Making the function a private method is the clean OO way; I would prefer this.
Using an anonymous namespace is the "new" C++ way; I'm using it time and again, e. g. for local internals (constants etc.) that may not leak to the outside, and are never ever thought to be used by derived classes. It's still not clean OO, though.
namespace { const int myMagicNumber = 0xdeadbeef; }
- Using
static
is the old C way; in my projects, depending on the context, I usually move these facilities into an anonymous namespace or make them a member when I find one.
-
3It doesn't matter whether it's clean OO or not - C++ is a multi-paradigm language. Either 1) or 2) is fine, mostly depending on personal taste.Sjoerd– Sjoerd2017年02月14日 12:14:35 +00:00Commented Feb 14, 2017 at 12:14
-
Just using "static" changes it from awful to somehow reasonable. So it's much better to just add static then to think about the other (better) methods and not doing them out of laziness.gnasher729– gnasher7292017年02月14日 13:17:26 +00:00Commented Feb 14, 2017 at 13:17
-
2Well using an anonymous namespace could be useful to reduce recompilation... but it would make sense only if you don't need much access to other members...Phil1970– Phil19702017年02月15日 04:22:01 +00:00Commented Feb 15, 2017 at 4:22
-
@Phil1970 Indeed, anonymous namespace and
static
would be simple (and IMHO awkward) ways to emulate some of the advantages of the Pimpl idiom (aka. D-Pointer).Murphy– Murphy2017年02月16日 09:31:22 +00:00Commented Feb 16, 2017 at 9:31 -
1You need to explain why it is 'clean OO' to make a function which takes a
render_info
and returns acl_float4
and has nothing to do with arenderer
a method ofrenderer
which breaks encapsulation (a change to its signature requires recompilation of client code).Pete Kirkham– Pete Kirkham2017年04月21日 14:18:58 +00:00Commented Apr 21, 2017 at 14:18
In general my answer would be the same as Steve Barnes' answer, with one addition:
If there is a future need to perform unit-testing on the sub-function that you have now extracted (e.g. with GTest), you will need to make that callable from the outside. This means the function prototype need to be declared in a *.h
file. Furthermore, it cannot be a private function inside a class, and it cannot be inside an anonymous namespace.
The question as to whether you should be unit-testing the publicly callable function or the now-extracted utility function is best left to you, since you have the best knowledge of your project. There are general guidelines which are covered in most unit-testing textbooks.
-
1One "trick" that I have seen for testable code that also respects scope limiters such as private is to have them marked PRIVATE_TESTABLE where this is defined as blank/public in in unit test builds and private/static otherwise.Steve Barnes– Steve Barnes2017年04月21日 17:06:13 +00:00Commented Apr 21, 2017 at 17:06