I would like to ask about the functional difference; maybe ask for an example scenario, where I should choose from one of the options in the main method below:
#include <iostream>
using namespace std;
class A{
private:
int x, y;
public:
A(int, int);
};
class B{
private:
int *x, *y;
public:
B(int, int);
~B();
};
A:: A(int x, int y){
this->x = x; this->y = y;
}
B:: B(int x, int y){
this->x = new int(x);
this->y = new int(y);
}
B:: ~B(){
delete this->x;
delete this->y;
}
int main(){
int x = 0, y = 0;
A* objA = new A(x, y); // line 1
B objB1(x, y); // line 2
B* objB2 = new B(x, y); // line 3
delete objA;
delete objB2;
return 0;
}
I understand that the second declaration in the main method B objB1(x, y) is obviously different from the other 2, but can someone please explain the functional difference between the constructors in lines labelled 1 and 3? Is there any bad practice in either of the declarations?
Thanks
NAX
UPDATE
First of all, I appreciate all of the answers that everyone is giving, I am really getting some good insight. I have edited the code above as a few of the answers pointed out that I haven't deleted the objects that I used, which is fair and all, but that was not the purpose of my question. I just wanted to gain some insight on the functional difference between the different approaches to creating the classes. And thanks to all that targeted that point. I am reading through the answers still.
"The functional difference..."
On Line 1 you allocate an object of type A on the heap through use of the new keyword. On the heap, space is allocated for the object to which objA points which means 2 ints are created on the heap, contiguously, in line with your ivar definitions.
On line 2 you create a new object of class B on the stack. It will have its destructor called automatically when it goes out of scope. However, when B is allocated, it will be allocated with space for two int pointers (not ints) which will in turn be allocated on the heap as you have specified in B's constructor. When objB1 goes out of scope, the pointers will be successfully deleted by the destructor.
On line 3 you create a new object of class B on the heap. Therefore, space is allocated on the heap for two int pointers (not ints), and then those ints, in turn, are allocated elsewhere on the heap through use of the new keyword. When you delete objB2, the destructor is called and therefore the two "elsewhere integers" are deallocated, and then your original object at objB2 is also deallocated from the heap.
In line with WhozCraig's comment, class A is the most definitely the preferred class definition of the two you have shown in your example.
EDIT (Comment response):
WhozCraig's link basically strongly discourages use of raw pointers. In light of this actually, yes, I agree, Line 2 would be preferred purely on the basis of memory management as B technically manages its own memory (though it still uses raw pointers).
However, I generally dislike (excessive) use of new inside classes as new is much slower than the equivalent stack (or non-new) allocation. I therefore prefer to new the entire class rather than the individual components as it only requires a single new call and all ivars are allocated in the heap anyway. (Better yet, placement new, but that is well beyond the scope of this question).
So in summing up:
Line 2 (class B) would be preferred on the basis of memory management, however even better than that would be:
A objAOnStack(x, y); // Avoids heap altogether
Line 1 is equal-best provided you wrap it in a smart pointer such as std::shared_ptr or std::unique_ptr or something similar.
Line 3 should not really be considered without a smart pointer wrapper (and it's generally better for performance to shy away from nested new anyway).
I usually prefer A-style objects unless there are compelling reasons to use the B pattern, merely because A-style objects are more efficient.
For example, when A objects are allocated, memory for 2 ints (probably 8 bytes on your machine) will be reserved and then initialized by the arguments passed to the constructor. When B objects are allocated, memory for 2 pointers to int will be reserved (also probably 8 bytes on your machine), but then when the B object is initialized in your constructor, each value that is passed will be copied to a newly created int (on the heap), thus using up 8 more bytes of memory total. So in this simple example, your B objects are taking up twice the memory as the A objects.
Furthermore, each time you want to access the values referred to by the x and y your B objects, it will require dereferencing the pointers, which adds a level of indirection and inefficiency (and, in many use cases, should also probably involve a NULL-check for safety, which adds a branch). And of course, there's the extra heap "cleanup" that has to be done whenever B objects are destroyed. (Which can gradually lead to heap fragmentation if lots of them are created and destroyed very frequently.)
Generally speaking, the way of class A is much preferable to class B. Unless you have a good reason, you should stick with designs similar to A. In simple cases and for simple data structures like these, the way class B is implemented can even be considered bad practice.
There are several reasons for this, and here they are in no particular order:
Class B does two more dynamic memory allocations than A. Allocating memory at runtime can be slow, and allocating and freeing a lot of blocks with various sizes can lead to what's called "memory fragmentation* (which is a bad thing.)
Instances of class B are larger than instances of class A. Instances of A are the size of two integers, which are commonly 32 bits each, which makes the whole instance to be 8 bytes. Instances of B require two pointers (which can be 32 or 64 bits each, depending whether your code is compiled for a 32 or 64 bit architecture) plus two actual integers (4 bytes each) plus some metadata that the heap allocator stores for each allocation, which might be anywhere from 0 to 32 bytes or more per allocation. So each instance of B is 8, 16 or (much) more bytes larger than each instance of A, while basically doing the same job.
Accessing the fields (x and y) inside instances of B are slower than the fields inside instances of A. When accessing members of an instance of B, all you have is the location of their pointers. So the CPU fetches the pointers, and then it can know the addresses of the actual integers that hold the values of x and y and that's when it can read or write their values.
In instances of A, you are sure that x and y are stored in consecutive memory addresses. This is the best case scenario to gain the most from CPU caches. In an instance of B, the addresses where the actual x and y are located can be far from each other and you'll get less benefit from the CPU cache.
In A, the lifetime of the members are exactly the same as the lifetime of the object containing them. For B, there is no such inherent guarantee. This is not the case in this simple example, but in more complex cases, specially in the presence of exceptions, this point becomes a clear and present danger. Programming errors (e.g. forgetting to delete one member in some rarely-executed path of the destructor) is also a problem in case of B.
Note that sometimes, decoupling the lifetime of objects from the member data are what you actually want, but this is not generally considered good design. Look up RAII pattern in C++ if you want to know more.
By the way, as is pointed in other comments, you must implement (or declare private) copy constructor and assignment operator for class B.
Due to the same reasons outlines above, you should try to avoid newing your data if you can, which means that among the lines labeled 1, 2 and 3, line 2 is actually the better method of making instances.
You should define a copy constructor and an assignment operator for your class B. Otherwise you will have serious problems with those pointers. Apart from this, there is no functional difference between lines 1 and 3. The only difference is in the implementation.
Having said this, there is no reason for using pointers inside B. If you need a fixed number of integers, use plain integers or plain arrays. If you need a variable number of integers, use std::vector. And if you really need to allocate dynamic memory, be very careful and consider using smart pointers.
If your class B contained only one [pointer to] integer, it could be something like:
class B
{
private:
int * x;
public:
B (int i) { x = new int(i); }
B (const B & b) { x = new int(*b.x); }
~B() { delete x; }
B & operator= (const B & b) // Corner cases:
{ //
int * p = x; // 1) b and *this might
x = new int(*b.x); // be the same object
delete p; //
return *this; // 2) new might throw
} // an exception
};
This code will do "The Right Thing (TM)" even in the corner cases commented.
Another option is:
#include <utility> // std::swap
class B
{
private:
int * x;
public:
B (int i) { x = new int(i); }
B (const B & b) { x = new int(*b.x); }
~B() { delete x; }
void swap (B & b)
{
using std::swap;
swap (x, b.x);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception
Though, if there are two pointers ---like in your example---, you have to call new twice. If the second new failed throwing an exception, you would want to automatically delete the memory reserved by the first new...
#include <utility> // std::swap
class B
{
private:
int * x;
int * y;
void init (int i, int j)
{
x = new int(i);
try
{
y = new int(j);
}
catch (...) // first new was OK but
{ // second failed, so undo
delete x; // first allocation and
throw; // continue the exception
}
}
public:
B (int i, int j) { init (i, j); }
B (const B & b) { init (*b.x, *b.y); }
~B() { delete x; delete y; }
void swap (B & b)
{
using std::swap;
swap (x, b.x);
swap (y, b.y);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception
If you had three or four [pointers to] ints... the code would get even uglier! That's where smart pointers and RAII (Resource Acquisition Is Initialization) really help:
#include <utility> // std::swap
#include <memory> // std::unique_ptr (or std::auto_ptr)
class B
{
private:
std::auto_ptr<int> x; // If your compiler supports
std::auto_ptr<int> y; // C++11, use unique_ptr instead
public:
B (int i, int j) : x(new int(i)), // If 2nd new
y(new int(j)) {} // fails, 1st is
// undone
B (const B & b) : x(new int(*b.x)),
y(new int(*b.y)) {}
// No destructor is required
void swap (B & b)
{
using std::swap;
swap (x, b.x);
swap (y, b.y);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception
Line 1 creates objA and leaves a memory leak because objA is not deleted. If it was deleted, members x and y would be deleted too. Also objA supports copy constructors and assignment operator. There will be no issues with these calls:
func1(*objA)
A objB = *objA.
If you do the same lines with objB2, you will get memory access violation because the same memory pointed by x and y will be deleted twice. You need to create private copy constructor and assignment operator to prevent that.
Regarding scenarios:
Line1 and 3 are good for returning the object to a calling function.
The calling function will need to take responsibility for deleting
it. In class B x and y can be pointers to a base class. So they can
be polymorphic.
Line2 is good for passing this object to a called function below the
call stack. The object will be deleted when the current function
exits.
Related
I am new to c++ so question would be elementary.
Lets say I have defined a class Foo and I create a vector of vectors in the following code:
namespace testme {
class Foo {
public:
Foo(int x): x_(x) { };
static vector<vector<int>> ReturnVecOfInts(int num) {
vector<vector<int>> ret(num);
for (int i = 0; i < num; i++) {
vector<int> tmp;
ret.push_back(tmp);
}
return ret;
}
}
When i call:
Foo::ReturnVecOfInts(5)
Is the vector of vectors created on heap or the stack. The reference is on the stack but I want to know whether it points to the heap since i want to return this object from a function.
This is important to me because clearly if these are allocated on the stack the vector of vectors would go out of scope and not usable outside the called function.
You're probably overthinking.
In your case, you're safe in code like this:
Foo f = Bar::GetFoo();
When you return objects from functions, in general, there may occur various optimizations (e.g. RVO, NRVO, etc.), but the bottom line is that your f object is safe to use.
Even if inside Foo you have a data member like std::vector which usually allocates its memory from the heap (you can customize this behavior using custom allocators), thanks to copy constructors, move constructors, destructor, etc. you are totally safe in returning it from functions, or copying Foo instances around.
EDIT I noted that you changed your code after I wrote my answer, returning a vector<vector<int>> instead of Foo. Again, what I wrote still applies.
Since C++11, when using the move assignment operator, should I std::swap all my data, including POD types? I guess it doesn't make a difference for the example below, but I'd like to know what the generally accepted best practice is.
Example code:
class a
{
double* m_d;
unsigned int n;
public:
/// Another question: Should this be a const reference return?
const a& operator=(a&& other)
{
std::swap(m_d, other.m_d); /// correct
std::swap(n, other.n); /// correct ?
/// or
// n = other.n;
// other.n = 0;
}
}
You might like to consider a constructor of the form: - ie: there are always "meaningful" or defined values stores in n or m_d.
a() : m_d(nullptr), n(0)
{
}
I think this should be rewriten this way.
class a
{
public:
a& operator=(a&& other)
{
delete this->m_d; // avoid leaking
this->m_d = other.m_d;
other.m_d = nullptr;
this->n = other.n;
other.n = 0; // n may represents array size
return *this;
}
private:
double* m_d;
unsigned int n;
};
should I std::swap all my data
Not generally. Move semantics are there to make things faster, and swapping data that's stored directly in the objects will normally be slower than copying it, and possibly assigning some value to some of the moved-from data members.
For your specific scenario...
class a
{
double* m_d;
unsigned int n;
...it's not enough to consider just the data members to know what makes sense. For example, if you use your postulated combination of swap for non-POD members and assignment otherwise...
std::swap(m_d, other.m_d);
n = other.n;
other.n = 0;
...in the move constructor or assignment operator, then it might still leave your program state invalid if say the destructor skipped deleting m_d when n was 0, or if it checked n == 0 before overwriting m_d with a pointer to newly allocated memory, old memory may be leaked. You have to decide on the class invariants: the valid relationships of m_d and n, to make sure your move constructor and/or assignment operator leave the state valid for future operations. (Most often, the moved-from object's destructor may be the only thing left to run, but it's valid for a program to reuse the moved-from object - e.g. assigning it a new value and working on it in the next iteration of a loop....)
Separately, if your invariants allow a non-nullptr m_d while n == 0, then swapping m_ds is appealing as it gives the moved-from object ongoing control of any buffer the moved-to object may have had: that may save time allocating a buffer later; counter-balancing that pro, if the buffer's not needed later you've kept it allocated longer than necessary, and if it's not big enough you'll end up deleting and newing a larger buffer, but at least you're being lazy about it which tends to help performance (but profile if you have to care).
No, if efficiency is any concern, don't swap PODs. There is just no benefit compared to normal assignment, it just results in unnecessary copies. Also consider if setting the moved from POD to 0 is even required at all.
I wouldn't even swap the pointer. If this is an owning relationship, use unique_ptr and move from it, otherwise treat it just like a POD (copy it and set it to nullptr afterwards or whatever your program logic requires).
If you don't have to set your PODs to zero and you use smart pointers, you don't even have to implement your move operator at all.
Concerning the second part of your question:
As Mateusz already stated, the assignment operator should always return a normal (non-const) reference.
I am attempting to use C++ for AVR programming using gcc-avr. The main issue is that there is no libc++ available and the implementation does not define any of the new or delete operators. Similarly there is no header to include using placement new is not an option.
When attempting to allocate a new dynamic object I am tempted to just do this:
Class* p = reinterpret_cast<Class*>(malloc(sizeof(Class)));
p->Init();
where Init() manually initializes all internal variables. But is this safe or even possible?
I have read that object construction in C++ is somewhat complex but without new or delete how do I initialize a dynamically allocated object?
To expand on the above question.
Using standard g++ and placement new it is possible to subvert constructors in two ways, assuming that C++ uses the same straightforward ways of alligning memory as C (code example below).
Using placement new to initialize any allocated memory.
Initialize allocated memory directly using class methods.
Of course this only holds if the assumptions are true that:
Memory layout of an object is fixed at compile time.
Memory allocation is only concerned with class variables and observers normal C rules (allocated in order of declaration aligned to memory boundary).
If the above holds could I not just allocated memory using malloc and use a reinterpret_cast to convert to the correct class and initialize it manually? Of course this is both non-portable and hack-ish but the only other way I can see is to work around the problem and not use dynamically allocated memory at all.
Example:
Class A {
int i;
long l;
public:
A() : i(1), l(2) {}
int get_i() { return i; }
void set_i(int x) { i = x; }
long get_l() { return l; }
void set_l(long y) { l = y; }
};
Class B {
/* Identical to Class A, except constructor. */
public B() : i(3), l(4) {}
};
int main() {
A* a = (A*) ::operator new(sizeof(A));
B* b = (B*) ::operator new(sizeof(B));
/* Allocating A using B's constructor. */
a = (A*) new (a) B();
cout << a->get_i() << endl; // prints 3
cout << a->get_l() << endl; // prints 4
/* Setting b directly without constructing */
b->set_i(5);
b->set_l(6);
cout << b->get_i() << endl; // prints 5
cout << b->get_l() << endl; // prints 6
If your allegedly C++ compiler does not support operator new, you should be able to simply provide your own, either in the class or as a global definition. Here's a simple one from an article discussing operator new, slightly modified (and the same can be found in many other places, too):
void* operator new(size_t sz) {
void* mem = malloc(sz);
if (mem)
return mem;
else
throw std::bad_alloc();
}
void operator delete(void* ptr) {
free(ptr);
}
A longer discussion of operator new, in particular for class-specific definitions, can also be found here.
From the comments, it seems that given such a definition, your compiler then happily supports the standard object-on-heap creations like these:
auto a = std::make_shared<A>();
A *pa = new A{};
The problem with using Init methods as shown in the code snippet in your question is that it can be a pain to get that to work properly with inheritance, especially multiple or virtual inheritance, at least when something during object construction might throw. The C++ language has elaborate rules to make sure something useful and predictable happens in that situation with constructors; duplicating that with ordinary functions probably will get tricky rather fast.
Whether you can get away with your malloc()-reinterprete_cast<>-init() approach depends on whether you have virtual functions/inheritance. If there is nothing virtual in your class (it's a plain old datatype), your approach will work.
However, if there is anything virtual in it, your approach will fail miserably: In these cases, C++ adds a v-table to the data layout of your class which you cannot access directly without going very deep into undefined behavior. This v-table pointer is usually set when the constructor is run. Since you can't safely mimic the behavior of the constructor in this regard, you must actually call a constructor. That is, you must use placement-new at the very least.
Providing a classless operator new() as Christopher Creutzig suggests, is the easiest way to provide full C++ functionality. It is the function that is used internally by new expressions to provide the memory on which the constructors can be called to provide a fully initialized object.
One last point of assurance: as long as you do not use a variable length array at the end of a struct like this
typedef struct foo {
size_t arraySize;
int array[];
} foo;
the size of any class/struct is entirely a compile time constant.
I have a bug which seems to cause access to memory which has already been cleared.
There are 2 classes - class B (which contains struct instances of class C and unique_ptrs of class D) and Class A which contains a vector of class B objects.
Here's the code structure of the area where the bug is caused:
void foo{
A localA(...);
bar(&localA);
baz(localA);
}
void bar(A* a) {
C c1 = constructLocalC1();
D d1 = constructLocalD1();
a.insertB(c1, &d1);
}
Note that insertB will call the constructor for class B - something like:
void A::insertB(C c, D* d) {
bVector.push_back(B(c, d));
}
B::B(C cIn, D* dIn) : c_(cIn) { d_ = make_unique<D>(*dIn); }
B {
public:
B(C c, D* d);
C c_;
std::unique_ptr<D> d_;
}
The implementation of constructLocalC1() looks something like (similar for constructLocalD1())
C constructLocalC1() {
C c1;
c1.blah = computeBlahParameter(); // blah is of type int
c1.bleh = computeBlehParameter(); // bleh is of type double
return c1;
}
The observation is that when baz tries to access (the copy of) c1 present in localA, the values in there are corrupted and not the same as the ones set by bar. My conclusion from this observation is that the vector which stores B is storing an element which has become de-allocated.
I know it is slightly complicated to understand the root cause through the code snippet here, as this is highly abstracted out - glad to provide more specific details which are required.
What are potential pitfalls and causes of memory leaks in this code snippet? What are good ways to approach the debugging?
Your problem probably is that you don't dynamically allocate memory on your objects inside bar.
If you create an object in a function that is not, explicitly or implicitly, dynamically allocated (using new, or by using temporary objects), then your objects are created on the stack, and they will be destroyed as soon as they come out of scope (in your case, when function returns). The one option is to allocate memory for the objects inserted in vector, but be extremely careful on memory handling and deallocation, as if not handled properly can result to memory leaks. You can also use smart pointers (Boost libraries have a great implementation of them but are also added on STL), that will prevent such situation, via RAII concept approach (For more on RAII, look on this topic: RAII and smart pointers in C++).
I'm getting acquainted with C++, and I'm having a problem with memory management. In C, whenever I'd want to reserve memory for any number of elements, regardless of type, I would just call malloc() and then initialize by hand (through a loop), to whichever value I wanted. With C++'s new, everything is automagically initialized.
Problem is, I've got a BattlePoint class which goes a little something like this:
class BattlePoint {
public:
BattlePoint(int x, int y) : x(x), y(y) { };
bool operator==(const BattlePoint &right);
virtual ~BattlePoint();
private:
int x, y;
};
As you can see, it takes a few x and y values through the initializer and then sets its own x and y from it. The problem is, this function will be called from a function which will allocate an array of them:
BattleShip::BattleShip(BattlePoint start, enum shipTypeSize size, enum shipOrientation orientation) : size(size), orientation(orientation) {
points = new BattlePoint[size]; // Here be doubts.
}
So, I need my BattleShip's point to hold an array of BattlePoints, each one with different initialization values (such as 0,1; 0,2; 0,3, etcetera).
Question is: how could I allocate my memory uninitialized?
Julian,
P.S.: I haven't done any testing regarding the way new works, I simple read Wikipedia's article on it which says:
In the C++ programming language, as well as in many C++-based
languages, new is a language construct that dynamically allocates
memory on the heap and initialises the memory using the
constructor. Except for a form called the "placement new", new
attempts to allocate enough memory on the heap for the new data. If
successful, it initialises the memory and returns the address to the
newly allocated and initialised memory. However if new cannot allocate
memory on the heap it will throw an exception of type std::bad_alloc.
This removes the need to explicitly check the result of an allocation.
A call to delete, which calls the destructor and returns the memory
allocated by new back to the heap, must be made for every call to new
to avoid a memory leak.
placement new should be the solution, yet it makes no mention on how to do it.
P.S. 2: I know this can be done through stdlib's vector class, but I'm avoiding it on purpose.
You need to use a std::vector. In this case you can push_back whatever you want, e.g.
std::vector<BattlePoint> x;
x.push_back(BattlePoint(1, 2));
If you ever find yourself using new[], delete, or delete[], refactor your program immediately to remove such. They are hideously unsafe in virtually every way imaginable. Instead, use resource-managing classes, such as std::unique_ptr, std::vector, and std::shared_ptr.
Regular new can be useful in some situations involving unique_ptr, but else avoid it. In addition, placement new is usually not worth it. Of course, if you're writing a resource-managing class, then you may have to use them as underlying primitives, but that's few and very far between.
Edit: My mistake, I didn't see the very last line of your question. Addressing it:
P.S. 2: I know this can be done through stdlib's vector class, but I'm
avoiding it on purpose.
If you have some campaign against the Standard Library, then roll your own vector replacement. But do not go without a vector class. There's a reason that it must be provided by all conforming compilers.
points = new BattlePoint[size]; // Here be doubts.
P.S. 2: I know this can be done through stdlib's vector class, but I'm avoiding it on purpose.
Most certainly there will be doubts! Use std::vector. Why wouldn't you? There is no reason not to use std::vector, especially if it solves your problem.
std::vector<BattlePoint> bpoints;
bpoints.reserve(size); // there, only alloc'd memory, not initialized it.
bpoints.push_back(some_point); // still need to use push_back to initialize it
I'm sure the question will come - how does std::vector only alloc the memory?!
operator new is the answer. It's the operator that gets called for memory allocation when you use new. new is for construction and initialization, while operator new is for allocation (that's why you can overload it).
BattlePoint* bpoints = ::operator new(size); // happens in reserve
new (bpoints[index]) BattlePoint(some_x, some_y); // happens in push_back
The comp.lang.c++ FAQ has useful things to say on the matter, including attempting to dissuade you from using placement new - but if you really insist, it does have a useful section on placement new and all its pitfalls.
To echo the above answers, I would most certainly point you towards std::vector as it is the best possible solution. Managing your own dynamic arrays in C++ is almost never a good idea, and is almost never necessary.
However, to answer the direct question -- in this situation you can create a default constructor and some mutators to get the desired effect:
class BattlePoint {
public:
// default constructor, default initialize to 0,0
BattlePoint() x(0), y(0) {};
BattlePoint(int x, int y) : x(x), y(y) { };
bool operator==(const BattlePoint &right);
virtual ~BattlePoint();
// mutator functions allow you to modify the classes member values
void set_x(int x_) {x = x_;}
void set_y(int y_) {y = y_;}
private:
int x, y;
};
Then you can initialize this as you are used to in C:
BattlePoint* points = new BattlePoint[100];
for(int x = 0; x < 100; ++x)
{
points->set_x(x);
points->set_y(x * 2);
}
If you're bothered by basically making the BattlePoint class publically mutable, you can keep the mutators private and introduce a friend function specifically for initializing the values. This is a slightly more involved concept, so I'll forgo further explanation on this for now, unless it is needed.
Since you asked :)
Create your BattlePoint class again with a default constructor and mutators, however this time leave the mutators private, and declare a friend function to use them:
class BattlePoint {
public:
// default constructor, default initialize to 0,0
BattlePoint() x(0), y(0) {};
BattlePoint(int x, int y) : x(x), y(y) { };
bool operator==(const BattlePoint &right);
virtual ~BattlePoint();
private:
// mutator functions allow you to modify the classes member values
void set_x(int x_) {x = x_;}
void set_y(int y_) {y = y_;}
int x, y;
friend void do_initialize_x_y(BattlePoint*, int, int);
};
Create a header file that will contain a local function for creating the array of BattlePoint objects. This function will be available to anyone that includes the header, but if named properly then "everyone" should know not to use it.
// BattlePoint_Initialize.h
BattlePoint* create_battle_point_array(size_t count, int* x, int* y);
This function gets defined in the implementation file, along with our friend function that we will "hide" from the outside world:
// BattlePoint_Initialize.cpp
#include <BattlePoint_Initialize.h>
namespace
{
// by putting this function in an anonymous namespace it is only available
// to this compilation unit. This function can only be called from within
// this particular file.
//
// technically, the symbols are still exported, but they are mangled badly
// so someone could call this, but they would have to really try to do it
// not something that could be done "by accident"
void do_initialize_x_y(BattlePoint* bp, int x, int y)
{
bp->set_x(x);
bp->set_y(y);
}
}
// caution, relies on the assumption that count indicates the number of
// BattlePoint objects to be created, as well as the number of valid entries
// in the x and y arrays
BattlePoint* create_battle_point_array(size_t count, int* x, int* y)
{
BattlePoint* bp_array = new BattlePoint[count];
for(size_t curr = 0; curr < count; ++curr)
{
do_initialize_x_y(bp_array[curr], x[curr], y[curr]);
}
return bp_array;
}
So there you have it. A very convoluted way to meet your basic requirements.
While, create_battlepoint_array() could in theory be called anywhere, it's actually not capable of modifying an already created BattlePoint object. The do_initialize_x_y() function by nature of being hidden in an anonymous namespace tucked away behind the initialization code cannot easily be called from anywhere else in your program. In effect, once a BattlePoint object has been created (and initialized in two steps), it cannot be modified further.