2

I have a generic array class which throws a logic_error if it's used with a non-primitive type.

Template Class:

#include <string>
#include <sstream>
#include <iostream>    

using namespace std;

#define NULL_ELEMENT        ((T)NULL)


template<class T> class Array
{    
public:    
    Array(const int size)
    {
        this->elements[size];
        this->size = size;
        ::fill_n(elements, size, NULL_ELEMENT); /* 1 */
    }


    // Output of the array
    string toString()
    {
        int i=0;
        stringstream ss;

        ss << "Array{ ";

        for( ; i<size-1; i++ )
        {
            ss << elements[i] << ", ";
        }

        ss << elements[i] << " }";

        return ss.str();
    }

    // ...

private:
    int size;
    T elements[];
};

Test Code:

Working (primitive type used):

Array<int> arr(5);
cout << arr.toString() << endl;

Array is filled with 0: Array{ 0, 0, 0, 0, 0 }

Fail (non-primitive type used):

Array<string> arr(size); // <-- Exception thrown here
cout << arr.toString() << endl;

Thrown Exception:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

This happens in Array class at when ::fill_() is called (/* 1 */).

I want to fill the whole array with the Null-Element of the type T (like 0 if int or NULL if pointer etc.) - without iterating over each element. memset() is not a good solution here, isnt it?

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
ollo
  • 24,797
  • 14
  • 106
  • 155
  • 3
    What is `T element[]`? It is non-standard. And what is `this->elements[size];` supposed to do? (looks like you're coming from Java!). – Nawaz Jan 05 '13 at 22:05
  • 5
    Don't initialize everything with NULL, initialize it with `T()`. `std::string` takes a `char *` in one constructor, so it accepts `NULL`, but will not initialize it with an empty string. If you want an empty string, default-construct it. – chris Jan 05 '13 at 22:06
  • @Nawaz: caught!. I want to create a generic element with the length given in the constructor. – ollo Jan 05 '13 at 22:09
  • @chris: You mean `::fill_n(elements, size, T())`? Fails too (`SIGSEGV` received). Do i get the null element with `T()`? – ollo Jan 05 '13 at 22:14
  • 2
    @ollo welcome to C++! Chris is correct, you're initialising the value-type `std::string` with `NULL` which makes the exception get thrown. Default construct things with `T()`. You've also not created the array `elements`, you'll have to create it with `new T[size]`. – Seth Carnegie Jan 05 '13 at 22:14
  • @ollo C++ is a difficult language, it would behoove you to read a good book on it before continuing. It is very unlike Java, and you'll get frustrated around every corner if you expect otherwise. – Seth Carnegie Jan 05 '13 at 22:16
  • 2
    @ollo, You get whatever the type decides. For something like `int`, that's 0 as per the spec, but if you make your own, you can provide a default constructor and make a default-constructed object be whatever you want, or use the one provided for you if there are no others. In the case of `std::string`, that's an empty string. For `std::vector`, an empty vector. – chris Jan 05 '13 at 22:19

1 Answers1

4

Here is what you should be doing. This is minimal code with correct skeleton of your class.

template<class T> 
class Array
{
     T  *m_elements;  //declare a pointer member 
     size_t m_size;   //count of the elements

public:    

    Array(size_t size) : m_size(size), m_element(new T[size]())
    {                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                     //    use member-initialization-list
    }

    ~Array(); //must define it

    Array(Array const & other); //must define it

    Array& operator=(Array const & other); //must define it

    Array(Array&& temporary); //better define it (in C++11)
    Array& operator=(Array&& temporary); //better define it (in C++11)

    //other
};

To know why you must define the destructor, copy-constructor and copy-assignment, better define move-constructor and move-assignment, see these (in that order):

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 6
    Thank you! `: m_size(size), m_element(new T[size]())` is the key :-). Btw. i have copyconstructor, operators etc. defined but not in my example. Solved my problem, thanks again! – ollo Jan 05 '13 at 22:27
  • 2
    @ollo: I would still recommend you to read the topics I provided this links of. They're *really* good and *important* to understand the concept. – Nawaz Jan 05 '13 at 22:28
  • 5
    And once you're done the mandatory Rule of Three stuff, switch to RAII: http://dl.dropbox.com/u/6101039/Modern%20C++.pdf. It's the modern way of using resources in C++, and good to use when you don't have any restriction on using it. – chris Jan 05 '13 at 22:32