Next revision
|
Previous revision
|
eliminate_char_arrays [2017/09/01 15:39] shane created |
eliminate_char_arrays [2017/09/01 16:09] (current) shane [Eliminating unnecessary String() constructor invocations] |
}; | }; |
</code> | </code> |
The resulting code changes elsewhere, to eliminate clumsy uses of things like ''sprintf()'' and //juce::String::copyToUTF8()'', etc. are too obvious (and embarrassing) to even list here. | The resulting code changes elsewhere, to eliminate clumsy uses of things like ''sprintf()'' and //juce::String::copyToUTF8()//, etc. are too obvious (and embarrassing) to even list here. |
| |
| ===== Use of "const char*" for string literals ===== |
| I do still use the ''char'' type in a very specific way in **VanillaJuce**, to declare a static array of string literals in ''SynthWaveform.cpp'': |
| <code cpp> |
| const char* const SynthWaveform::wfNames[] = { |
| "Sine", "Triangle", "Square", "Sawtooth" |
| }; |
| </code> |
| As Jules pointed out in his list of code issues, it's acceptable and preferable to use string literals (which the C++ compiler will interpret as being of type ''const char*'') to initialize //juce::String// variables, and in place of //juce::String//-typed function parameters. This is because //juce::String// has been defined to include a constructor which takes a ''const char*'' argument, and therefore, the C++ compiler will silently invoke this constructor function to turn the given literal string into a //juce::String// instance automatically. In terms of the above table of waveform names, I could have made it an array of //juce::String// objects, but this would be redundant. |
| |
| Ordinarily, I get uneasy whenever the C++ compiler silently inserts function calls in this way, because it obscures the flow of control. In this case I'm OK with it, because it is a well-established JUCE programming convention. |
| |
| ===== Eliminating unnecessary String() constructor invocations ===== |
| A perfect example of why it's a good idea to avoid writing ''String("xyz")'' and just use the literal ''"xyz"'' arose in some code I used in //SynthParameters::getXml()//, which is a series of function calls like this: |
| <code cpp> |
| xml->setAttribute(String("masterLevel"), masterLevel); |
| </code> |
| I had used the ''String("xyz")'' construct simply because I didn't know much about JUCE's XML functions, and had copy-pasted the code from an example I found elsewhere. When I looked, though, I noticed that the //juce::XmlElement::setAttribute()// function is actually declared as |
| <code cpp> |
| void XmlElement::setAttribute (const Identifier& attributeName, const double number) |
| </code> |
| along with many related definitions, for different data-types in the second argument. In every case, however, the first argument is not a //juce::String// at all, but something called a //juce::Identifier//. Presumably, the C++ compiler is accepting my //juce::String// arguments by silently invoking an appropriate //juce::Identifier// constructor I wasn't even aware of. Depending how good its optimization is, this might be quite inefficient. The lesson is clear: whenever possible, use simple string literals, and trust that the JUCE library has defined appropriate constructors to perform whatever conversions may be necessary. All the ''setAttribute'' calls in my //SynthParameters::getXml()// implementation now look like this: |
| <code cpp> |
| xml->setAttribute("masterLevel", masterLevel); |
| </code> |
| |
===== Use of const char* for string literals ===== | |
| |
| |