6
class item
{
    int i;

  public:
    item(int no) {

    }
};

I want to check the constructor parameter. If it is found to hold a negative value, then object creation should be stopped.

Exceptions can not be used here as the targeted system does not support exceptions.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
sukumar
  • 161
  • 2
  • 6
  • 1
    "Exceptions can not be used here as the targeted system does not support exceptions." you flagged this question as [c++], but exceptinos are part of standard C++. So in fact you are not really programming C++, but rather a C++-like language. As the answers point out, expcetions are the way that C++ handles this problem. – Raedwald Sep 09 '11 at 12:47

6 Answers6

6

There is no way to stop the creation of an object without throwing. The best you can do is set an "invalid parameter" flag that you have to check afterwards, and if true discard the object without using it.

With the requirements you have, it would probably be better to use a factory method to create the objects -- this way, you can make the checks before calling the constructor:

class item
{
    int i;
public:
    static item* create(int no) {
        if (no < 0) {
            return 0;
        }

        return new item(no);
    }

private:
    item(int no) {

    }
};

You could use this like

item* myItem = item::create(-5);
if(!myItem) {
    // failed
}

However, this forces you to allocate all item instances on the heap.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Jon
  • 428,835
  • 81
  • 738
  • 806
3

Exceptions are the way designated by the standard to perform this task; there's no other way to abort completely the object creation.

On the other hand, you can give your class some "state" member that specifies that the class was not correctly constructed and check it at every method call (a bit like how iostream classes work).

class item
{
    int i;
    bool validState;
public:
    item(int no) : validState(true)
    {
        if(/* no is invalid */)
        {
            validState = false;
            return;
        }
        /* ... */
    }

    bool ValidState() { return validState; }

    SomeType DoSomething()
    {
        if(!ValidState())
        {
            // do nothing/report the error to the caller
        }
        // ...
    }
}

IMO it's cumbersome, but if you don't have exceptions and want to create objects via a public constructor there's nothing much better than this.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
2

You cannot stop object construction mid-way, without throwing an exception. That said, you may outright prevent construction of item objects which fail a precondition, by moving the precondition and object-creation responsibilities to a separate factory function, and making the constructors private (to disallow all other ways to construct the object):

class item {
       int i;

   public:
       static item* create( int no )
       { 
           return no < 0 ? NULL : new item( no );
       }

   private:
       item() { ... }
       item( int no ) { ... }
};
Brian Fearon
  • 151
  • 5
  • THIS answer should be the accepted one, at least right at the top...! Most Cpp like (hard to use wrong). Maybe you woult want to elaborate on the caveats though (item::create() returns a pointer, using placement new, ...) – Florian Apr 20 '19 at 12:13
  • NOT **placement** new - should read: 'caveats of new' (like on the heap, dynamically allocated) – Florian Apr 20 '19 at 13:52
1

Three options.

  1. Use a flag in your class to track full construction - but you'll have to test that in each method.
  2. Make item a wrapper, such that the internals are held in a class that is constructed if the arguments are good, but in all the methods, you'll have to test the internals - so no different to 1 anyway.
  3. Use a factory to return a smart pointer if the arguments are good.

My preference in this scenario is the last one.

Nim
  • 33,299
  • 2
  • 62
  • 101
0

Put the object into an error state (use a boolean) and then all methods should return an error.

ie

class Item
{
   int i;
   bool errorState;
   public:
      Item(int n) : i(n) {
         errorState = i < 0;
      }
      bool method()
      {
        if (errorState) return false;
         ..... do stuff here

         return true;
      }
}
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
-1

You can do it at compile time with necessary warning flags ON (e.g. -Wall in gcc).

class item
{
public:
    item(unsigned int no) {}  // item takes only +ve value
};

Compiler will warn you if a -ve value is passed.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 2
    http://codepad.org/o1Z1Di4O - unsigned values are defined to wrap around. You might get a warning for this at high warning levels, but I would _never_ recommend relying on it. – Lightness Races in Orbit Sep 09 '11 at 11:44
  • 1
    @Tomalak, I do get a warning in gcc. Without exceptions, I see this one as one of the feasible solutions. – iammilind Sep 09 '11 at 11:47
  • Yuk. Conversion from signed is defined/needs no diagnostic, `-1` wraps to `UINT_MAX`, & you let a very wrong number past. A diagnostic's only guaranteed if `item` is brace-initd from a signed literal/var. How many ways fail that? (1) if the arg *is* `unsigned` *but* was converted from a `signed` in the many other ways that allow narrowing; (2) if `item` is from a `make` function that doesn't use braced-init, e.g. my `std::make_unique()`; (3) probably many other code paths. `unsigned` makes sense if <0 can't arise, but if -ves are possible or sentinels, this silently 'succeeds' & blows up later – underscore_d Sep 15 '18 at 20:12