Disclaimer: I'm unsure if this questions fits this forum, but it might.
Preamble: This question is about a project in C++98 and has mixed C and C++ sources. It also has global variables, and a lot of bad code.
I have a large code base (an old one) with an int theVar[] variable which represents a property of an object which is a collection. The model used to have only one instance of "the object". A new requirement came along which called for having more than one instance of the object, so I had to refactor this int[] into an int[][], where the first index specified the instance of the object. Changing the type of the variable in the declaration allows the compiler to warn me of places in the code in need of updating, but it misses things such as:
if (theVar[i]) ...
And more.
How can I perform this refactoring in the safest way?
NOTE
There is some really good advice in the comments, I appreciate it, this question might not have a best answer, but the comments have given me some good directions to follow.
Related
Qt makes heavy use of the PIMPL idiom in their development process: https://wiki.qt.io/D-Pointer
As I've read here: "The name 'd-pointer' stems from Trolltech's Arnt Gulbrandsen, who first introduced the technique into Qt, making it one of the first C++ GUI libraries to maintain binary compatibility even between bigger release.". But nobody says what "D" stands for.
So what does the "D" stand for in D-Pointer?
From this page Data Sharing with Class (an old docs from QT), it says:
Before we can share an object's private data, we must separate its interface from the private data using an idiom called "d-pointer" (data pointer)
So, d-pointer means data-pointer
I'll add my own answer, since I remember the day it happened.
I was trying to extend something while maintaining binary compatibility, and noticed that there was a pointer called 'data' that I could reuse for a different purpose. So I made a private class for implementation-related data (a pimpl), put both the old data and my new data there, and since the existing name seemed to fit I kept the name.
I abbreviated it from data to d after a short meeting later on the same day, where we agreed that the pattern I'd invented stumbled upon was good and we should use it widely, and that d-> was short enough and unique enough to be used everwhere as a mark of implementation-specific fields.
At the same meeting, we decided to put implementation-specific data in d-> as a matter of policy from then on, mostly in order to keep the number of includes down, but also to keep the declared API clean in general. Fewer private variables in the class declaration means few opportunities for error, fewer temptations, fewer things that can conflict with subclass naming and so on. Better hygiene.
I was looking for implementation of SCC algorithm in C++ and there's one weird line which is clearly beyond my comprehension.
Graph<V,E> gt(SIZE(g)), res(SIZE(g)), *tab[] = {this,>};
I don't understand *tab[] = {this,>};
I assume it is a pointer but still don't get it at all so I'd be glad If someone could explain it to me. I've been using C++ for almost 6 years and I've never seen this kind of pointer before.
This appears to be three different declarations:
Graph<V,E> gt(SIZE(g));
Graph<V,E> res(SIZE(g));
Graph<V,E> *tab[] = {this,>};
It's probably someone's idea of making the code more minimal, but it arguably impacts readability in a pretty severe way.
Why tab even exists I don't know, it depends on how it's used in other parts of the code. Is this some kind of bizarro linked list?
tab is an array of pointers to Graph<V, E>, and is initialized with two elements: pointer this, and a pointer to newly created gt.
I'm working on an old large code base with a colleague. The codebase uses a significant number of std::shared_ptr and previous developers had a fondness for long property names (m_first_username for example).
Some methods in our code access a number of those properties so our code tends to be very verbose:
if (m_first_username->isSomethingOrOther() || m_second_username->isOtherOrSomething()...
So to make the code more readable my colleague wants to use more std::shared_ptr & with local scope:
const std::shared_ptr<...> &tmp = m_first_username->returnsASharedPtr()
tmp->isSomethingOrOther();
Something I disagree with because of the shared pointer use count.
What is the best way to make this code more readable? Keeping using constant references to shared_ptr, use std::weak_ptr or live with the long lines of code?
As per #nwp's comment -the proper way to alias a variable name locally would be:
auto& v1 = m_first_user_name;
If you want to go the route of the "returnAsSharedPointer" you posted in the question, what you'd want to use in the classes of m_first_user_name and m_second user_name is the standard C++ enable_shared_from_this.
On the whole, though it's primarily opinion-based, I believe you'll find that most experienced C++ developers will find the new code less readable than the old code. There is nothing wrong with long, descriptive variable names.
I am trying to make an architecture for a MMO game and I can't figure out how I can store as many variables as I need in GameObjects without having a lot of calls to send them on a wire at the same time I update them.
What I have now is:
Game::ChangePosition(Vector3 newPos) {
gameobject.ChangePosition(newPos);
SendOnWireNEWPOSITION(gameobject.id, newPos);
}
It makes the code rubbish, hard to maintain, understand, extend. So think of a Champion example:
I would have to make a lot of functions for each variable. And this is just the generalisation for this Champion, I might have have 1-2 other member variable for each Champion type/"class".
It would be perfect if I would be able to have OnPropertyChange from .NET or something similar. The architecture I am trying to guess would work nicely is if I had something similar to:
For HP: when I update it, automatically call SendFloatOnWire("HP", hp);
For Position: when I update it, automatically call SendVector3OnWire("Position", Position)
For Name: when I update it, automatically call SendSOnWire("Name", Name);
What are exactly SendFloatOnWire, SendVector3OnWire, SendSOnWire ? Functions that serialize those types in a char buffer.
OR METHOD 2 (Preffered), but might be expensive
Update Hp, Position normally and then every Network Thread tick scan all GameObject instances on the server for the changed variables and send those.
How would that be implemented on a high scale game server and what are my options? Any useful book for such cases?
Would macros turn out to be useful? I think I was explosed to some source code of something similar and I think it used macros.
Thank you in advance.
EDIT: I think I've found a solution, but I don't know how robust it actually is. I am going to have a go at it and see where I stand afterwards. https://developer.valvesoftware.com/wiki/Networking_Entities
On method 1:
Such an approach could be relatively "easy" to implement using a maps, that are accessed via getters/setters. The general idea would be something like:
class GameCharacter {
map<string, int> myints;
// same for doubles, floats, strings
public:
GameCharacter() {
myints["HP"]=100;
myints["FP"]=50;
}
int getInt(string fld) { return myints[fld]; };
void setInt(string fld, int val) { myints[fld]=val; sendIntOnWire(fld,val); }
};
Online demo
If you prefer to keep the properties in your class, you'd go for a map to pointers or member pointers instead of values. At construction you'd then initialize the map with the relevant pointers. If you decide to change the member variable you should however always go via the setter.
You could even go further and abstract your Champion by making it just a collection of properties and behaviors, that would be accessed via the map. This component architecture is exposed by Mike McShaffry in Game Coding Complete (a must read book for any game developer). There's a community site for the book with some source code to download. You may have a look at the actor.h and actor.cpp file. Nevertheless, I really recommend to read the full explanations in the book.
The advantage of componentization is that you could embed your network forwarding logic in the base class of all properties: this could simplify your code by an order of magnitude.
On method 2:
I think the base idea is perfectly suitable, except that a complete analysis (or worse, transmission) of all objects would be an overkill.
A nice alternative would be have a marker that is set when a change is done and is reset when the change is transmitted. If you transmit marked objects (and perhaps only marked properties of those), you would minimize workload of your synchronization thread, and reduce network overhead by pooling transmission of several changes affecting the same object.
Overall conclusion I arrived at: Having another call after I update the position, is not that bad. It is a line of code longer, but it is better for different motives:
It is explicit. You know exactly what's happening.
You don't slow down the code by making all kinds of hacks to get it working.
You don't use extra memory.
Methods I've tried:
Having maps for each type, as suggest by #Christophe. The major drawback of it was that it wasn't error prone. You could've had HP and Hp declared in the same map and it could've added another layer of problems and frustrations, such as declaring maps for each type and then preceding every variable with the mapname.
Using something SIMILAR to valve's engine: It created a separate class for each networking variable you wanted. Then, it used a template to wrap up the basic types you declared (int, float, bool) and also extended operators for that template. It used way too much memory and extra calls for basic functionality.
Using a data mapper that added pointers for each variable in the constructor, and then sent them with an offset. I left the project prematurely when I realised the code started to be confusing and hard to maintain.
Using a struct that is sent every time something changes, manually. This is easily done by using protobuf. Extending structs is also easy.
Every tick, generate a new struct with the data for the classes and send it. This keeps very important stuff always up to date, but eats a lot of bandwidth.
Use reflection with help from boost. It wasn't a great solution.
After all, I went with using a mix of 4, and 5. And now I am implementing it in my game. One huge advantage of protobuf is the capability of generating structs from a .proto file, while also offering serialisation for the struct for you. It is blazingly fast.
For those special named variables that appear in subclasses, I have another struct made. Alternatively, with help from protobuf I could have an array of properties that are as simple as: ENUM_KEY_BYTE VALUE. Where ENUM_KEY_BYTE is just a byte that references a enum to properties such as IS_FLYING, IS_UP, IS_POISONED, and VALUE is a string.
The most important thing I've learned from this is to have as much serialization as possible. It is better to use more CPU on both ends than to have more Input&Output.
If anyone has any questions, comment and I will do my best helping you out.
ioanb7
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
First thing, I am not looking for a tool that is going to produce an unmaintainable C code from an existing cpp code-base. It is a requirement from a client, so I cannot just use the CPP code base itself.
I am trying to work out a work-flow, so that I can convert the code-base from CPP to C incrementally without breaking the code. I have thought out a few things using the "extern C" approach
Classes to Structs
Member functions of the Classes will be converted to Struct_name_FunctionName format.
In case of a function being re-used by 2 classes, I plan to use function pointers.
Replace overloaded operators like +,- etc with actual functions. Eg a Add_, Sub_ etc
Can you folks add anymore ?
and point out potential pit-falls ?
I cannot share the code-base because of NDA.
The code base isn't huge in itself. Its got around 50 cpp files, saw some 100 odd classes.
Thanks in advance.
P.s I have gone through some other questions that sound similar. But they don't really have the work-flow that I am looking for.
[Closing] : Although the post has been put on hold because it is too broad, many of the comments were in fact useful. I am clearer on what needs to be done than before. Thank you.
Well, there's a very long list you'll have to tackle. Without claiming to be complete, you also need:
Virtual function support (not impossibly hard, function pointer table)
Constructors and destructors (Reasonable mapping to ordinary functions, lot of work)
Exceptions and stack unwinding (extremely hard)
Missing C++ library functions and classes (lot of work)
But don't kid yourself. std::map<std::string, std::pair<int, int>> is a very straightforward class that stores two ints for each string. The C translation of that class is an outright mess. MyMap["five,three"] = std::make_pair(5,3) can easily become 100+ lines of C code.
If your C++ code makes extensive use of OO constructs - particularly inheritance and polymorphism - you might wish to look at some C libraries that mimic this in C. qobject (from the qemu source tree) is one I know well, but better known (to nearly everyone bar me) is http://en.wikipedia.org/wiki/GObject which comes from glib. Nowadays, that isn't tied up with GUI code.
The advantage here is that you can change the language in use without making too many changes to the program flow.
glib also provides a fair number of other useful library constructs.
Following the advice to take the GObject as an example how C++-like code is done in C, there's one thing you can try out:
Translate the C++ code to Vala
Generate C code from Vala compiler.
Vala is a C#-like language; except that you'll have to repeat "public" or "private" in every function signature, as well as get rid of pointer-star in class types in use, there's no much things you'll have to do.
Of course, the generated C code will look the same ugly as from the other generators, but at least there are some short ways how to make it a "maintainable" code (the main problem is that every object created in Vala results in incrementing reference counter in C code, which isn't always necessary).
The GObject model can be a nice instruction/example as to how to translate C++ constructs into the same in C. If you don't use exceptions (Vala does! :) ), there should be no trouble with that. Of course the main guidelines are:
Normal methods: use the pointer to object as first argument. The function name is NAMESPACE_CLASSNAME_METHODNAME.
Virtual methods: you have to create a "characteristic object", pointed by the "object" of that class, which contains pointers to functions. The class's characteristic objects are usually created in GObject in functions that return pointer to that object - the object itself is lazily created and saved in a static local variable.
Overloading: add name-distinguising parts (Vala does not support overloading, even in constructors - constructors use special syntax for calling named constructors)
Templates: expand in place :)
Derivation: single derivation only (as in Vala as well), make the first field of the "derived class" structure the field of type of the "base class" structure.
Calling methods from base classes: use C cast. If you follow the point 5, you should simply cast the structure of derived class object to the structure of the base class.