0

Inside a method can one create an uninitialised object from the class?

Here's some context: imagine a class where the constructors all allocate memory:

class NumberArray
{
  size_t m_Size;
  int *m_Numbers;

public:
  NumberArray() { m_Size = 1; m_Numbers = new int[1]; m_Numbers[0] = 0; }

  // . . . other methods for manipulating or constructing . . .

  ~NumberArray() { delete[] m_Numbers; }

  // What if I had a method that concatenates two arrays?
  NumberArray ConcatenateWith(const NumberArray &) const;
};

Inside such a method one would desire to create an uninitialised object of class NumberArray, and then 'construct' a new object based on this and the object in the parameter? AKA:

NumberArray NumberArray::ConcatenateWith(const NumberArray &other) const
{
  // Mystery manner of creating an uninitialised NumberArray 'returnObject'.
  returnObject.m_Size = m_Size + other.m_Size;
  returnObject.m_Numbers = new int[returnObject.m_Size];
  std::copy(m_Numbers, m_Numbers + m_Size, returnObject.m_Numbers);
  std::copy(other.m_Numbers, other.m_Numbers + other.m_Size, returnObject.m_Numbers + m_Size);
  return returnObject;
}

What's the best way of doing this? Basically, I don't want the default constructor to create a size 1 array that I will just delete and then allocate a new array for again anyway.

Veltas
  • 1,003
  • 6
  • 19
  • 3
    I think the way you phrased your question shows that you have a deep misconception about objects and their construction. I suggest reading more C++ material. – Andy Prowl Feb 04 '13 at 19:58
  • 1
    Adding to Andy Prowl's comment, I suggest you read "C++ Object Model" by Lippmann – Aniket Inge Feb 04 '13 at 19:58
  • 1
    @Aniket: Keep in mind some information in that book is outdated/wrong. Might be better to stick with other stuff. – GManNickG Feb 04 '13 at 20:05
  • Okay guys, it sounds like I didn't explain it properly. Let me try again, I will edit this. – Veltas Feb 04 '13 at 20:31
  • 1
    Please, do provide an example. What's this composition of an object with another object? Perhaps you just need a different constructor? – Alex Feb 04 '13 at 21:13
  • Example has been provided. – Veltas Feb 04 '13 at 23:47

4 Answers4

1

It's not entirely clear what you are trying to do, but if all you want is to create a new instance of the class and not have a constructor other than the default constructor called then do just that.

All you have to do is create a private constructor, that has a different signature from the default constructor and which does not allocate memory (or differs in whatever way you need it to differ from the default constructor); then simply have your class invoke that constructor internally, when necessary.

Nik Bougalis
  • 10,495
  • 1
  • 21
  • 37
1

What you're asking for is placement new. This looks something like this:

#include <cstdlib>
#include <new>

void* mem = std::malloc(sizeof(T)); // memory for a T (properly aligned per malloc)

T* x = new (mem) T; // construct a T in that memory location
x->~T();            // destruct that T

std::free(mem); // and free the memory

Doing this correctly (in an exception-safe manner with properly managed and aligned memory) is not a trivial task. You need to be careful about the lifetime of your objects.

For your question, you are describing exactly what std::vector does. It allocates raw uninitialized memory and constructs inserted elements directly into that memory. And lots of its code is dedicated to just getting the lifetime and memory management correct and exception safe!

You should strongly prefer to use std::vector instead of writing it yourself.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
0

There is no well-defined way, as far as I'm aware, to create an object without invoking it's constructor. This is regardless of whether you have access to its public interface or not, though you could implement a private or protected constructor if you want to restrict who can invoke it. There is otehrwise no restrictions on creating new instances of a class from its own internal methods, in fact it is quite common to define a private constructor and a static public method that create instances of said object if you want to restrict under which conditions said object can be created.

If you want to, you can allocated sufficient memory for an object and reinterpret_cast a pointer to that memory to a pointer of the type you want. This usually works for POD's, but since many implementations (if not all) of polymorphic inheritance in c++ adds a pointer to a vtable to polymorphic instances this approach will usually, if not always, fail for those.

In short, create a private constructor and have a static method invoke it and then do any other work that you need is my recommendation.

OnePie
  • 425
  • 3
  • 10
0

I think this may be similar to what you want, an 'anonymous' class of sorts:

struct test {
    virtual void doSomething() {
        puts("test");
    }
};

struct a {
    test *t() {
        struct b : test {
            void doSomething() {
                puts("b");
            };
        };

        return new b;
    };
};

int main()
{
    a a;

    a.t()->doSomething(); // outputs 'b'
}

However, due to slicing and how new works on C++, you must return a pointer and the 'anonymous' type must have a name, even if it's restricted only to the function.

If you could edit the OP and clarify exactly what you wish to accomplish by this, maybe we could help you more.

Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • Wouldn't that cause a memory leak? – Veltas Feb 04 '13 at 21:12
  • @Veltas correct. Another thing to be careful of when returning pointers. This was simply a PoC of what the OP may want, it wasn't a bug-free solution by any means. – Richard J. Ross III Feb 04 '13 at 21:13
  • Why do you return a pointer, why not return the object itself? – Veltas Feb 04 '13 at 23:21
  • @Veltas because of [slicing](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c). Basically, you cannot return a subclass properly within a method because of some weirdness with the way C++ handles objects vs C# or java. – Richard J. Ross III Feb 04 '13 at 23:23
  • But I'm not trying to return a subclass, and surely if I were then I'd say so and it would return it properly provided the signature of the function specified it returned the exact same type of sub-class? – Veltas Feb 04 '13 at 23:50