Am reading through (the) C++ Core guidelines and encountered this rule: "Don’t declare a variable until you have a value to initialize it with" https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es22-dont-declare-a-variable-until-you-have-a-value-to-initialize-it-with
It describes the following code as bad:
SomeLargeType var;
if (cond) // some non-trivial condition
Set(&var);
else if (cond2 || !cond3) {
var = Set2(3.14);
}
else {
var = 0;
for (auto& e : something)
var += e;
}
Unfortunately this point fails to describe a way to how to solve this exact issue. Sometimes you just have to initialize a large object differently depending on a condition.
The only circumvent that comes to my mind is something like:
SomeLargeType * var;
if (cond) // some non-trivial condition
var = new SomeLargeType(123);
else if (cond2 || !cond3) {
var = new SomeLargeType(3.14);
}
However even if I use a smartpointer, this feels somehow unnecessary/unsafe and most of all, worse than the initial way.
What is the optimal solution?
You can use a function. Also, don't use bare pointers with ownership (I assume that there's a guideline for this too). Example:
std::unique_ptr<SomeLargeType>
make_something(bool cond, bool cond23)
{
if (cond)
return std::make_unique<SomeLargeType>(123);
else if (cond23)
return std::make_unique<SomeLargeType>(3.14);
else
return nullptr;
}
// usage
std::unique_ptr<SomeLargeType> var = make_something(cond, cond2 || !cond3);
If there's no way for this function to be reusable, then a lambda might be appropriate, as shown by Sopel
First, there is no undefined behaviour in the original sample code: all possible conditions are taken care of (by the final else block). However, there is potential undefined behaviour in the answers so far given, as they replace the 'good' code in the aforementioned else block with, effectively, no initialisation and the return of a nullptr, which may later be the subject of an attempted dereference.
Also, there is no real need here to complicate matters by replacing the instance variable with a pointer (and this also changes the nature/logic of the code).
Using a lambda (as suggested in the link provided by StaceyGirl) is certainly a good way to go (probably the best, but that may be subjective). However, to keep the logic the same as the original code, one can apply the lambda to the object, rather than to a pointer, as so:
SomeLargeType var = [&]() {
if (cond) { // some non-trivial condition
SomeLargeType v1;
Set(&v1);
return v1;
}
else if (cond2 || !cond3) {
SomeLargeType v2 = Set2(3.14);
return v2;
}
else {
SomeLargeType v3 = 0;
for (auto& e : something) var += e;
return v3;
}
}();
Here, unlike in the original code (where a default constructor is first called, then one of three others), a constructor for SomeLargeObject will only be called once¹ and there will be no undefined behaviour. It is this initial call to the (potentially very expensive) default constructor that, I presume, is the reason for this being cited as an example of "bad code."
¹ If there are any doubts about how often the constructors are called, I can provide a complete MCVE (with some minor modifications to avoid the undefined for (auto& e : something) line), if such is requested.
An immediately invoked lambda can be used as an alternative to a named function.
SomeLargeType* var = [&]() {
if (cond) // some non-trivial condition
return new SomeLargeType(123);
else if (cond2 || !cond3)
return new SomeLargeType(3.14);
else
return nullptr;
}();
Note that some types may not provide a default constructor, in which case it's impossible to have a lazy initialization without using a boxing type.
This can also improve performance when the type is not trivially constructible.
https://godbolt.org/z/_V8t2T
Related
I have a function which processes data that comes as a sequence. Because of this, I need to know the value of certain variables from the last function call during the current function call.
My current approach to doing this is to use static variables. My function goes something like this:
bool processData(Object message){
static int lastVar1 = -1;
int curVar1 = message.var1;
if (curVar1 > lastVar1){
// Do something
}
lastVar1 = curVar1;
}
This is just a small sample of the code; in reality I have 10+ static variables tracking different things. My gut tells me using so many static variables probably isn't a good idea, though I have nothing to back that feeling up.
My question: Is there a better way to do this?
An alternative I've been looking into is using an object whose fields are lastVar1, lastVar2, etc. However, I'm not sure if keeping an object in memory would be more efficient than using static variables.
Your question has a taste of being purely about style and opinions, though there are aspects that are not a matter of opinion: multithreading and testing.
Consider this:
bool foo(int x) {
static last_val = -1;
bool result = (x == last_val);
last_val = x;
return result;
}
You can call this function concurrently from multiple threads but it wont do the expected. Moreover you can only test the function by asserting that it does the right thing:
foo(1);
assert( foo(1) ); // silenty assumes that the last call did the right thing
To setup the preconditions for the test (first line) you already have to assume that foo(1) does the right thing, which somehow defeats the purpose of testing that call in the second line.
If the methods need the current object and the previous object, simply pass both:
bool processData(const Object& message,const Object& previous_message){
if (message.var1 > previous_message.var1){
// Do something
return true;
}
return false;
}
Of course this just shifts the issue of keeping track of the previous message to the caller, though thats straight-forward and requires not messing around with statics:
Object message, old_message;
while ( get_more( message )) {
processData(message, old_message);
old_message = message;
}
Context: I'm trying to memoize an object of a template class. Right now, the class is a deeply nested data structure full of unique pointers, and so doesn't have a copy constructor (and so would be impossible to cache, as far as I know). However, in the future, I would like to allow memoization if a copy constructor is available. I tried the following code:
// some function here... {
static std::unordered_map<State, Result> cache;
return [c, ToValue](State state) {
if (cache.find(state) != cache.end()) {
std::cout << "retrieving Literal from cache\n";
if (std::is_copy_constructible<Result>::value) {
return cache[state];
}
}
// calculate and return a Result
This code doesn't compile because Result doesn't have a copy constructor. Is there any way to get around this? Google is being quite unhelpful.
I'm presuming the error you are getting is that return cache[state]; cannot be compiled when the object is not copy-constructible. To fix that you can write:
if constexpr (std::is_copy_constructible<Result>::value) {
return cache[state];
}
If you are still having trouble then post a MCVE that has the error.
As others have commented, the question is rather ill-defined and a bit confused, but do you need to actually copy an object in order to cache it?
Actually, no. You can use std::shared_ptr to share ownership of the object between the creator, any consumers, and the cache. If nothing else, this is much more efficient if your object is a complex one. It will also work for any type of object, copyable or not.
Example (I'm going to use the word Key rather than State, for what I hope are obvious reasons).
Given these declarations:
class MyKey
{
// ....
};
class MyCacheableObject
{
// Constructor
MyCacheableObject (int a, int b, int c) { ... }
// ...
};
static std::unordered_map<MyKey, std::shared_ptr<MyCacheableObject>> cache; // or std::map
You can do this (please note that there are other ways to make a std::shared_ptr, see here):
std::shared_ptr<MyCacheableObject> CreateCacheableObject (int a, int b, int c)
{
return std::make_shared<MyCacheableObject> (MyCacheableObject (a, b, c));
}
And then, assuming you have a key you plan to use to retrieve the object from the cache later on, you can do:
MyKey someKey = ...;
std::shared_ptr<MyCacheableObject> newObject = CreateCacheableObject (1, 2, 3);
// ... setup / use `newObject` in whatever way is appropriate to your use-case
cache [someKey] = newObject;
And you can of course retrieve the object from the cache (if it's in there) via:
auto retrievedObject = cache.find (someKey)
if (retrievedObject != cache.end())
...
So this question is not about whether an object is copyable at all. It's about (shared) ownership and std::shared_ptr takes care of all that for you, you don't really have to think about it. Oy vay.
There's a live demo, to show that this all compiles, here.
I need to check if my object Course is in a safe empty state.
Here is my failed attempt:
const bool Course::isEmpty() const {
if (Course() == nullptr) {
return true;
}
else {
return false;
}
}
Constructors:
Course::Course() {
courseTitle_ = new char[21]; // name
courseTitle_ = '\0';
credits_ = 0;//qtyNeeded
studyLoad_ = 0;//quantity
strcpy(courseCode_, "");//sku
}
Course::Course(const char* courseCode, const char* courseTitle, int credits , int studyLoad ) {
strcpy(courseCode_, courseCode);
courseTitle_ = new char[21];
strcpy(courseTitle_, courseTitle);
studyLoad_ = studyLoad;
credits_ = credits;
}
Apprently, Doing course() == nullptr is not truly checking if the object is in safe empty state, also checking individual variables if they are set to 0 will not work in my program. i need to check if the entire object was set to a safe empty state.
Edit: Some of you are asking what my empty() function is suppose to use. There is a tester that is suppose to test if my isEmpty() works well.
bool isEmptyTest0() {
// empty test
sict::Course c0;
return c0.isEmpty();
}
bool isEmptyTest1() {
// empty test
sict::Course c0("", "title", 3, 3);
return c0.isEmpty();
}
bool isEmptyTest2() {
// empty test
sict::Course c0("code", "", 3, 3);
return c0.isEmpty();
}
bool isEmptyTest3() {
// empty test
sict::Course c0("code", "title", -1, 3);
return c0.isEmpty();
}
bool isEmptyTest4() {
// empty test
sict::Course c0("code", "title", 3, -1);
return c0.isEmpty();
}
bool regularInitTest() {
// regular
sict::Course c5("OOP244", "Object-Oriented Programming in C++", 1, 4);
return (!c5.isEmpty()
&& !strcmp("OOP244", c5.getCourseCode())
&& !strcmp("Object-Oriented Programming in C++", c5.getCourseTitle())
&& (c5.getCredits() == 1)
&& c5.getStudyLoad() == 4
);
}
Note that in regularInitTest() my assignment operators work fine, but it never passes !c5.isEmpty() because it fails. Hopefully i explained it correctly.
Most probably here is what you should do to make the tests pass.
In the 2nd (4-argument) constructor, do some checking of the input, e.g. check if credits is positive. Do check all arguments for all possible errors you can imagine, including those in isEmptyTest0..4. If there is an error, initialize the object the same way as the 1st (0-argument) constructor does. If there is no error, initialize the data members from the arguments.
Here is how to implement the isEmpty method: it should return true iff all the data members of the object have the empty/zero/default value, as initialized by the 1st (0-argument) constructor.
The notion safe empty state in itself still doesn't make sense, but the concept the professor is trying to teach does make sense. I'll try to summarize my understanding here. Constructors can receive invalid arguments, based on which it's not possible to initialize a meaningful and valid object. The programmer should add code for error checking and handling everywhere in the program, including constructors. There are multiple approaches to do input validation and error handling in constructors, e.g. 1. throwing an exception; 2. aborting the entire program with an error message; 3. initializing the object to a special, invalid state; 4. initializing the object to a special, empty state. (This is also an option, but it's strongly disrecommended: 5. keep some data members of the object uninitialized.) Each of these approaches have pros and cons. In this assignment, the professor wants you to implement #4. See the 2nd paragraph in my answer how to do it.
When the professor asks for a safe empty state, he most probably means that you should be doing input validation in the constructor, and in case of an error doing #4 rather than #5.
I agree with pts that safe empty state is ill-defined.
The missing principle, it seems to me after reading the comments, is Resource Acquisition Is Initialization (RAII). A constructor is a transaction, in a way: you get either
a valid object, or
an exception.
Valid here is defined by the class. Usually it means that the passed parameters were incorporated into the object, and all required resources were successfully allocated and/or found.
Aborting the program is rarely an option, and returning an error (from a constructor) never is. Constructing an invalid object is usually done only in environments where exceptions are prohibited.
There is a special case: the default constructor. Sometimes it's desirable to "make an empty" thing that will be fully initialized later.
Consider std::string. It can be constructed with a value, and throws an exception if memory cannot be allocated. Or it can be constructed without a value, and later assigned one. Your class could be similar, in which case safe empty just means a state that the user would be happy to destroy when calling the "init" function. You don't have to test every member variable; you just have to check something that will be true only for a completely initialized object.
Then there's the question of "is valid". An "empty" object can be "initialized", but it can't be used. It's not "valid" for use until fully initialized, whether at construction, or via the 2-step with a default constructor and a subsequent "init".
There is a widely accepted idiom for testing whether an object is "is valid" or not: a user-defined conversion to void *:
...
public:
operator void*() { return is_valid()? this : nullptr; }
...
where is_valid() may be a private function. With that in place, the user can test his instantiated object thus:
class A;
A foo();
...
if (!foo) { foo.open(...); }
I know I haven't answered your question, exactly. I hope I've provided some background that makes it easier for your to answer it yourself.
I have code that does something like this:
//datareader.cpp
if (populateFoo(dataReader, foo))
else {
// Do other things with the reader.
}
//foo.cpp
bool populateFoo(const DataReader &dataReader, Foo &foo)
{
if (dataReader.name() == "bar") {
foo.bar() = dataReader.value();
return true;
} // More similar checks.
return false;
}
I feel like it's misleading to have an if statement with conditions that have side-effects. However, I can't move the body of the populateFoo function into datareader.cpp. Is there a good way to restructure this code so we get rid of this misleading if statement, without duplicating the body of populateFoo()?
Do you have a strong hatred of local variables? If not:
bool populated = populateFoo(dataReader, foo);
if (populated)
{
// Do things
}
else
{
// Do other things
}
The compiler will almost certainly emit exactly the same code, so performance shouldn't be an issue. It's a readability/style choice, ultimately.
The obvious solution seems like storing the result of populateFoo and using it for determining whether populateFoo was successful:
bool fooPopulated = populateFoo(dataReader, Foo);
if (!fooPopulated)
//Do other things with reader.
However, I don't find the original difficult to understand, and it's a fairly well-established practice to both modify values and test the success of the modification in the same line. However, I would change it to:
if (!populateFoo(dataReader, Foo)
//Do other things with reader.
How about:
if (!populateFoo(dataReader, foo)) {
// Do other things with the reader.
}
Edit: The title of the question suggests it is the fact the if statement is empty that bothers you but the body seems more that it is the side effect that is the concern. I think it's fine in C++ to have conditions in if statements that have side effects but this won't solve your issue if you want to avoid that.
Having conditions with side-effects is quite common - think about calling a C API and checking its return code for errors.
Usually, as long as it's not buried in a complicated expression where it may be missed by the casual bystander, I don't bother to do particular refactorings, but, in case you wanted to make it extra clear (or document what the return value is, which is particularly useful in case of booleans) just assign it to a variable before the branch - or even just a few comments may help.
You could split the populateFoo function into two, a const check function (shouldPopulateFoo) that checks the condition, and another non-const function that performs the actual modifications (populateFoo):
//datareader.cpp
if (shouldPopulateFoo(dataReader)) {
populateFoo(dataReader, foo);
}
else {
// Do other things with the reader.
}
//foo.cpp
bool shouldPopulateFoo(const DataReader &dataReader) /* const */
{
return (dataReader.name() == "bar");
}
void populateFoo(const DataReader &dataReader, Foo &foo) /* non-const */
{
assert(shouldPopulateFoo(dataReader));
foo.bar = dataReader.value();
}
Note that when using these functions as class methods, you could declare the check function const.
How about:
if (populateFoo(dataReader, foo) == false) {
// Do other things with the reader.
}
It is very readable, I often see code where the returned value from function is a signal to the caller for branching in the caller. The else block with empty if block bothers me more then the side effects inside the if (). There is a sense of reverse logic, which is alway less readable.
I think many of you have this kind of code somewhere:
int foo;
switch (bar) {
case SOMETHING: foo = 5; break;
case STHNELSE: foo = 10; break;
...
}
But this code has some drawbacks:
You can easily forget a "break"
The foo variable is not const while it should be
It's just not beautiful
So I started wondering if there was a way to "improve" this kind of code, and I got this little idea:
const int foo = [&]() -> int {
switch (bar) {
case SOMETHING: return 5;
case STHNELSE: return 10;
...
}
}();
Note: the first pair of parentheses it not mandatory, but MSVC++ doesn't support this yet
You can use the same trick with if-else where the ternary operator would be too complicated, variables that require to be passed by pointers to be initialized (like for DirectX functions), etc.
My questions are:
Is there anything wrong with this code that I didn't see?
Do you find it better than the one above?
g++ seems to inline the function, but do you think that all compilers will do so?
EDIT: this is what I mean by "DirectX functions"
_xAudio2 = [&]() -> std::shared_ptr<IXAudio2> {
IXAudio2* ptr = nullptr;
if (FAILED(XAudio2Create(&ptr, xAudioFlags, XAUDIO2_DEFAULT_PROCESSOR)))
throw std::runtime_error("XAudio2Create failed");
return std::shared_ptr<IXAudio2>(ptr, [](IUnknown* ptr) { ptr->Release(); });
}();
This is a fairly common technique in other languages. Almost every high-level feature of Scheme is defined in terms of lambdas that are immediately called.
In JavaScript it is the basis of the "module pattern", e.g.
var myModule = (function() {
// declare variables and functions (which will be "private")
return {
// populate this object literal with "public" functions
};
})();
So an anonymous function is declared and immediately called, so that any internal details are hidden and only the return value is exposed externally.
The only downsides is that on a casual reading of the code, the return statements will appear to be returning from the outer function (there was intense controversy about this during the Java lambda wars). But this is just something you have to get used to once your language has lambdas.
There are many language features in an imperative language like C++ which would benefit from being able to return a value (rather than being like a void function). For example, if has an alternative, the tertiary operator expr ? a : b.
In Ruby pretty much all statements can be evaluated, so there is no need for a separate syntax where a return value can be supplied. If C++ worked that way, this would mean things like:
auto result = try
{
getIntegerSomehow();
}
catch (const SomeException &)
{
0;
}
I don't see any reason at all to use a switch case in such a case. Any decent compiler will generate just as fast code with if statements as with a switch case.
if(bar == SOMETHING)
foo = 5;
else if(bar == STHNELSE)
foo = 10;