You are here:

C++/Overloading the 'new' operator for arrays.

Advertisement


Question
Hi,

I have a dataSet class which as a member variable has:

Concept* concepts;

The class Concept has the following constructor:

Concept(int caseNum);

Well, I'm trying to do something like this:

concepts = new Concept[numberOfConcepts]

The only thing is this will call the default constructor and I want to apply the constructor above.

If 'concepts' was not an array I know how to do it, i.e.:

concepts = new Concept(theCaseNum);

But how can I call the constructor above when 'concepts' is an array? I tried something like this:

concepts = new Concept[numberOfConcepts](theCaseNum);

which of course did not work.

Nobody I talked to have given me a satisfactory answer, so I would really appreciate your help.


Regards,
Adrien


Answer
Sorry, but creating built-in arrays of objects be they automatically allocated (locally on the stack), statically allocated (locally or globally with internal or external linkage) or dynamically allocated (using operator new []) - always and only ever call the default constructor for each object in the array.

If you think about it this makes sense. In general each object in an array would be different some how from the others so any parameters passed would need to be different for each object so how do you pass the different parameters to each object?

Maybe you have a special case where you want a number of identically created objects but such cases are probably in the minority. C and C++ have no mechanism that allows you to call an array of functions which is effectively what you are asking. Remember constructors are special member functions to which the compiler adds its own housekeeping code to ensure objects are constructed correctly. At the end of the day when you say:

       MyType MyObject( param );

You are calling a constructor member function it just has this syntactic sugar coating that makes it expressed nicely. It could be considered to be:

       MyType MyObject.MyType( param );

But the compiler already knows what the name of the constructor is as you have already specified the type name so the MyType constructor function name is redundant.

The point is as constructing an object is much the same as a member function call:

       MyObject.AnOperation( param );

How do you call a member function for an array of objects?

      MyType MyObjects[10];

      MyObjects.AnOperation( param ); // ?

What would it mean? Call the member function on each element passing the same single set of parameters?

Maybe it would be nice to be able to do this but C and C++ do not support it directly. This type of requirement, as I suggested above is a subset of calling operations on elements and you can always do this using a loop:

       for ( int j=0; j<10; ++j )
       {
         MyObjects[j].AnOperation( param );
       }

Which is a much more general mechanism, and C++ is quite large and complex enough as it is!

There are several ways around this, and I discuss a few below.

The most obvious fix is to set the case number after the array has been created for each element using a member function.

If the case number is truly fixed at compile time for all objects you could derive a sub-class of Concept that contained a default constructor that set the base case number to the required value. You could even make it a class template that took the case number as a parameter:

       template < int CaseNum >
       class FixedCaseConcept : Concept
       {
       public:
         FixedCaseConcept : Concept( CaseNum ) {}
       };
        
You could use such a class like so:

       FixedCaseConcept<10> *
         = new FixedCaseConcept<10>[numberOfConcepts];

In this example I have used 10 as the case number. I used a literal value to underscore the fact that this technique _only_ works if the case number is constant i.e. known at compile time.

Another option would be to use std::vector<Concept> - and create one Concept with the required case number then use this as a template object (template here is used in the sense of something used to make copies, not in the C++ class template or function template sense). std::vector<> has a constructor which allows you to create a vector of n elements each of which is a copy of a passed object:

       Concept concept( theCaseNum );
       std::vector<Concept> concepts(numberOfConcepts, concept);

The other C++ standard library sequence containers std::deque and std::list have equivalent constructors.

The nice thing about the standard library containers is that they take care of the memory management for you and provide a useful set of operations and can be used via iterators with the standard library algoritms. I suggest you learn about the facilities of the C++ standard library  - it could save you a lot of pain! For online information on some of the C++ standard library see http://www.sgi.com/tech/stl/. I would also recommend you read a few book such as Effective STL by Scott Meyers and The C++ Standard Library a Tutorial and Reference by Nicolai M. Josuttis.


Other options would include re-factoring your design. If you use many Concept objects that are identical maybe the class needs to be split into the common part to do with the case number and the rest of the concept. In fact you should probably do this. Maybe you create a UseCase class that contains, for example the case number, then have it directly associated with its set of concepts. Of course you may need to have a back reference from each concept to the case to which it applies and you are back where you started - but if you work it carefully this may no be necessary. Also you could consider if you really require the services of an array or vector. Would a list be better? Could you store pointers to the concepts? If you use a list of concepts then you can create each one when required, passing any parameters required then add it to the list. Note that if you use any of the standard library containers to store pointers to objects then you need to delete each element manually before deleting the container.

       class UseCase
       {
       public:
         UseCase ( int aCaseNum ) : iCaseNum {}
         ~UseCase ();

         AddConcept( Concept const & aConcept );

       private:
         int          iCaseNum;
         std::list<Concept>    iConcepts;
       };

       UseCase::AddConcept( Concept const & aConcept )
       {
       // add a copy of the passed concept to the end of the list
         iConcepts.push_back( aConcept );
       }

Here I have shown part of a hypothetical UseCase class. The concept may well need to have no knowledge of its associated use case as each use case contains its own list of concepts. You would then use the two classes like so:

       UseCase case( caseNumber );
       Concept concept;
       // Set up concept...

       case.AddConcept( concept );

Now concept is _copied_ to the list held by case, so you can safely modify concept after the call to AddConcept including destroying it.
Note: all code typed in straight off the top of my head so beware typos and other errors!  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.