c++ - Checking if an Object is in empty state - c++

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.

Related

What is the correct way to return an 'Invalid Value' type in C++, without the use of pointers?

I often use -1 as the invalid value type when returning from a function, where the input yields incorrect output. For instance, writing an indexing function where the index is out of bounds, instead of throwing an exception, -1 can be returned. But when writing a function that has negative values as possible return types, this technique does not work. What is the correct way to return an invalid type value in such instances?
The technique I use mostly is to set the return type to be of type *int, and return a Pointer to NULL. But, that requires all return values to be of a pointer type, which seems like an extra overhead to the function. Is there an accepted standard for returning values in such cases?
In newer C++, I'd suggest using std::optional<>; if you don't yet have it, boost::optional<>.
One option would be to let your function take a bool& as an output parameter used to indicate if the returned value is valid.
int myFunc(bool& valid); // sets 'valid' to true if result is usable, false otherwise
Users can then do
bool valid = false;
Int result = myFunc(valid);
if (!valid) {
// Handle error
}
// Use result
Not the most pretty solution, but it does the job.
Apart from the answer I provided above, there's a very clean, continuation-passing solution (given you're non-virtual):
template<typename Success, typename Failed>
void parse( const std::string& str, Success s, Failed f )
{
auto a = start_parse(str);
if( a.problem() )
return f(); // you _might_ have an error code here
s( finish_parse(str, a) );
}
Then you might customize by:
Success:
[&i] (int i_) { i = i_; }
out(i), where out(int& output_) returns the above lambda for output_
actual code doing something useful
function to continue with
Failed:
[&i]{ i = 0; }, `[&i]{ i = nullopt; }, or any other default value
[] { throw MyFavouriteException(); }
retry logic
std::terminate()
[]{} if you don't care (or if you're 100% sure it'll succeed)
It might look a little verbose, but IMHO:
it's trivial to read
any other schematics can be mimicked, even if there's no default c'tor
easy to change as well
'you don't pay for what you don't use', can surely be optimized away
every schematic is visible and apparent from code:
for default value, caller sets it, not callee or global
std::optional<> and default value are handled the same
for exception, caller knows better what to throw
for no action, you don't have to lookup the implementation to know this
for std::terminate(), well, you know what to expect
if you 'speak' CPS, you might actually continue and save an if / catch / etc.
The only issue I see is constructor initializer lists. Any thoughts on this?

Conditions on a constructors arguments [duplicate]

This question already has answers here:
How to handle failure in constructor in C++?
(8 answers)
Closed 7 years ago.
Is it possible to check the arguments of a constructor for certain constraints and if they're not met the object is not created and return a value to tell it failed to be created .
for instance .
Class Device
{
string id;
Device(string ID)
{
If (ID.Length != 7)
{
//Do not create Object
}
id == ID;
}
}
Here I only want 7 char long id String , not less not more ! if its not 7 char I don't want the Object created is it possible to do this ?
I couldn't think of any solution to this other than external function check which is something I want to stay away from !
The usual way would be to check the condition, and if it's not met, throw an exception.
Another possibility would be to accept an array of 7 characters, so the code won't compile if something else is passed. This tends to be trickier to get to work well in general though (e.g., it usually won't work if somebody passes an object of the wrong type, even something like a string that actually does contain 7 characters).
A sort of intermediate point would be to create a type specifically to hold your string of 7 characters, and throw an exception in its ctor if the length is wrong. This can give a little more granularity so it's easier to know what's wrong when the exception is thrown, as well as assuring that creating the Device object will succeed if you pass it a valid DeviceName (or whatever name you prefer) object.
You can throw an exception.
https://stackoverflow.com/a/7894215/2887128
Class Device
{
string id;
Device(string ID)
{
If (ID.Length != 7)
{
throw invalidObjectParametersException;
}
id == ID;
}
}
You could also adjust your design and wrap construction in some sort of factory.
One option I can think of is to throw an error if the condition is not met and catch that error in the function that creates the object.
Yes, you can implement a valid method, which will return if the created object is valid. In order to do that, without creating your real object, you would have to create an internal struct, which would become a private member of the owner class:
Class Device
{
struct DeviceImplementation {
string id;
Device owner;
DeviceImplementation (Device *owner, const string &id):
owner(owner),
id(id)
{
}
};
std::unique_ptr<DeviceImplementation> implementation;
public:
Device(const string &ID)
{
If (ID.Length != 7)
{
//Do not create Object
} else
implementation=std::unique_ptr<DeviceImplementation>(new DeviceImplementation(this, ID));
}
bool isValid() const {return implementation!=nullptr;}
}
No, a constructor can only return an object (or raise an exception).
If you want the chance to verify parameters or context, you should make:
a) the constructor private (so it cannot be called from outside the class anymore)
b) provide a static public method that returns an object (or, for example, NULL if it failed), and inside this method do your tests, and if they are successful call the private constructor and return the created object.
Of course, the outside code needs to able to handle a NULL return (or whatever you chose to do to signal that it failed).
This is a simple and common solution, but you can make up others with similar ideas.

dereferencing this causes Segmentation fault

I have the following functions
LinearScheme::LinearScheme() {
cout << " empty constructor" << endl;
}
void LinearScheme::init(
int tableId,
std::string &basePath,
std::vector<size_t> &colElemSizes,
TupleDescMap &tupleDescMap,
size_t defaultMaxFragmentSize,
int numCols,
BoundBases &bounds,
std::vector<int> &colsPartitioned )
{
// This linear scheme ignores bounds
// it could be improved to use colsPartitioned for ordering (TODO)
cout << "init Linear Scheme " << endl;
*this = LinearScheme(); //SEGFAULTS HERE
cout << "after cons here?" << endl;
// init private fields
this->tableId_ = tableId;
this->basePath_ = basePath;
this->colElemSizes_ = colElemSizes;
this->numCols_ = numCols;
this->tupleDescMap_ = tupleDescMap;
this->numFragments_ = 0;
this->defaultMaxFragmentSize_ = defaultMaxFragmentSize;
// fragmentSizesFilename_ init
fragmentSizesFilename_ = basePath_ + boost::lexical_cast <string>(tableId_)
+ "_cs";
struct stat st;
// open existing file if exists. Create new otherwise.
if (stat(fragmentSizesFilename_.c_str(), &st) == 0) // file existed
openExisting();
else
createNew();
}
The reason I am initializing in init rather than constructor is because LinearScheme extends a PartitionScheme (super class with virtual methods) class and another class does that where the constructor is used recursively.
I have a QuadTree class which does the same initialization because each QuadTree constructor is applied recursively. *this = QuadTree(bounds, maxSize) line in the init function of QuadTree class works just fine.
however, this line in the other subclass (LinearScheme) *this = LinearScheme() cause a Seg fault.
Any ideas why this might happen?
EDIT
Also replacing the line:
*this = LinearScheme()
with this:
*this;
or removing it overall gets rid of the Seg Fault ... why?
Sounds like incorrect factory method / builder / deferred construction usage. For many of these object creation patterns function that constructs your objects should be a static method because there doesn't yet exist an instance to manipulate. In others you potentially manipulate an already constructed instance. In either case if you are actually constructing the object of the class type within the function you should be using new and eventually returning it.
If you are instead going for a helper method to assist with initialization then you simply shouldn't be constructing the object within the method itself, and you should just be initializing parts of it within your helper.
A factory pattern example:
LinearScheme* LinearScheme::create(...all_your_args....) {
/* construct the thing we are building only if it
* pass any arguments into him that he can handle directly if you'd like
*/
LinearScheme *out = new LinearScheme(...);
/* do whatever else you have to do */
....
return out;
}
or this helper of sorts that you seem to want
/* this time let's just do 'init' on your object */
void LinearScheme::init(....args....) {
/* possibly check if init has been done already */
if ( this->init ) return;
/* proceed to do your initialization stuff
* but don't construct the 'this' instance since it should already exist
*/
this->init = true; //so we don't init again if you don't need multiple init's
}
Alternatively you can consider the delegate constructor methods in C++11 alex mentions.
However neither of these really strikes me as being the actual problem here.
It's not working because either you probably don't even have a valid *this to deference. This could be because of your usage, or it could be because one failed to create potentially because of infinite recursion.
Here's a wikipedia link on the pattern: http://en.wikipedia.org/wiki/Factory_method_pattern
Given what you have said about having to keep passing a dozen arguments around both to parent classes and for your recursive construction, one suggestion you could consider is making a small config struct that you pass along by reference instead of all the discrete parameters. That way you don't have to keep adjusting every signature along the way each time you add / remove another parameter.
The other idea is to seperate entirely the construction of one of your objects from the responsibility of knowing how, where, and when they should be contructed and inserted into your hierarchy. Hard to say without understanding how you will actually be using LinearSchme and what the interface is.
"...in the other subclass (LinearScheme) *this = LinearScheme()"
"The LinearScheme constructor is empty: LinearScheme::LinearScheme()"
if *this is a subclass of LinearMethod, LinearMethod's constructor should already have been called and this line is useless. Besides it calls assignment operator - is it properly defined?
It is better to rely on built-in mechanism of constructing of objects. If you want to avoid code repetition, use C++11 delegating constructors feature. It was specially designed to eliminate "init" methods.
Although, "If there is an infinitely recursive cycle (e.g., constructor C1 delegates to another constructor C2, and C2 also delegates to C1), the behavior is undefined."
So it is up to you to avoid infinite recursion. In your QuadTree you can consider creating nullptr pointers to QuadTreeNode in constructor.

What should getObjByName() return?

I was working on some c++ code like this:
//c++ code
class MovieInfo;
MovieInfo getMovieInfoByName(String movieName)
{
//search the movieInfoList with movieName
if(FOUND)
return movieInfo;
//TODO: **what should i return if the movieInfo can't be found in the list?**
}
The question is what should i return if the movieInfo can't be found in the list?
You have several options:
Define the MovieInfo class such that an "invalid" instance is possible (similarly to how a default-constructed std::thread doesn't represent an actual thread) and return such an instance.
Make it a precondition of getMovieInfoByName() that the name corresponds to a valid movie info, and simply return a random value if it doesn't (as "violating preconditions leads to undefined behaviour").
Throw an exception when the name is not found.
Return something like boost::optional<MovieInfo>.
Give getMovieInfoByName() an extra parameter of type MovieInfo which would be used as the return value in case no match for the name is found.
It all depends on your intended use of the function.
It depends on the context and preconditions that must be met. For example if you are not sure whether the list contains such a movie by the time you call it, then it would be reasonable to do:
bool getMovieInfoByName(const std::string& movieName, MovieInfo& movieInfo)
{
...
if (FOUND) {
movieInfo = ...;
return true;
}
return false;
}
since the caller will most likely have to know whether the movie with such a movie exists or not.
If it shouldn't happen that getMovieInfoByName will not find the movie, i.e. the caller should already know whether the list contains such a movie by other means, then it is perfectly reasonable to throw an exception since it is exceptional state and rather indicates the wrong usage of this method.
There's also a design pattern called Null Object, which is based on constructing an object, state of which can indicate whether it is a valid / initialized object or it is a dummy instance representing NULL.
In this case the caller would most likely still have to check whether appropriate MovieInfo instance has been returned and this class should provide a method such as bool isValid();.

Null checking the null object pattern

The main goal of the Null Object Pattern is to ensure that a usable object is provided to the client. So we want to replace the following code...
void Class::SetPrivateMemberA() {
m_A = GetObject();
}
void Class::UseA() {
if (m_A != null) {
m_A.Method();
} else {
// assert or log the error
}
}
...with this implementation:
void Class::SetPrivateMemberA() {
m_A = GetObject();
}
void Class::UseA() {
m_A.Method();
}
The problem I am thinking of is that GetObject() still returns an object, a NULL Object or otherwise. I like the idea of not checking for null repeatedly and trusting that the object sent back is usable, but why wouldn't I just do that in the first implementation?
Is the advantage of the Null Object pattern just a slight increase in trust to clean up code? With the second implementation, is it not still a good practice to check that it is not null before calling A.Method()?
You're correct that, if you're sure you're never returning nulls, just skip the null check before calling the method in your first implementation. Likewise, if you do need to do something special in the case that UseA() needs to do something differently on a null object, that you need to explicitly check for a null object anyway. However, what null object pattern really helps with is those situations where it doesn't really matter.
Take, for example, most observer patterns. If you implement your observer pattern as a member of your class for which there can only be one observer, and want to announce to the observer that your class did something, it doesn't matter to the class whether the observer is null or not.
This is also illustrated with empty container classes, which are essentially the null object pattern: Instead of returning a null container from a query, you simply return an empty container. For things like iterating through all entries of a container, it often won't matter whether it's empty or not, so getting rid of the need of a null check makes the code more maintainable/more readable. However, if you want to populate a view of your data set, you still need to explicitly show a different "No entries." that checks for an empty container.
Edit for clarity
One problem is only looking at it from the call site. Like most design patterns, this needs to encompass both sides to be fully utilized. Consider:
public PossiblyNull GetSomethingNull()
{
if (someBadSituation())
return null;
else
return SomehowProduceSomething();
}
vs
public PossiblyEmpty GetSomethingEmpty()
{
if (someBadSituation())
return StaticEmptySomething();
else
return ProdueSomethingYay();
}
Now, your call code, instead of looking like
public void DoSomethingWithChild(Foo foo)
{
if (foo != null)
{
PossiblyNull bar = foo.GetSomething();
if (bar != null)
bar.DoSomething();
}
}
it can be
public void DoSomethingWithChild(Foo foo)
{
if (foo != null)
foo.GetSomething().DoSomething();
}
With the second implementation, is it
not still a good practice to check
that it is not null before calling
A.Method()?
No. If you know that m_A is not null, then the check is superfluous; it's an example of paranoid coding. What harm does it do? It complicates your code - unnecessarily; it makes it harder to read, harder to debug.