-1

In this little code i wanna create a vector like std::vector, but implemented by myself. I'm sorry but i don't have idea about to solve it, if somebody can help me with that will be great.

template <typename T>
struct vector {
private:
    typedef T type;

    type *m_array;
    size_t m_size;

public:
    vector() { }
    template <typename ... Args>
    vector(Args&&... a) {
        m_size = (size_t) sizeof...(a);
        m_array = (type*) malloc ( m_size * sizeof(type) );
        m_array = {a...};
    }
    ~vector() {
        free(m_array);
    }
    size_t size() {
        return m_size;
    }
    type operator[](size_t pos) {
        return m_array[pos];
    }
};

template <typename ... Ts>
size_t count ( Ts ... args ) {
    return (size_t)( sizeof...(args) );
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> v {3,2,4,5};
    printf("The v size is: %d", v.size());

    for(int i = 0; i < v.size(); ++i)
        printf("Value for v [ %d ] : %d", i, v[i]);

    system("pause>nul");
    return 0;
}

The error in C++ Builder(Embarcadero) is the next:

[bcc32c Error] vector.cpp(29): excess elements in scalar initializer
  vector.cpp(49): in instantiation of function template specialization 'vector::vector' requested here
user4581301
  • 33,082
  • 7
  • 33
  • 54
Emanuel Clur
  • 95
  • 1
  • 9
  • 4
    Take a look at [`std::initializer_list`](https://en.cppreference.com/w/cpp/utility/initializer_list) – Kevin Nov 28 '18 at 23:47
  • 4
    Consider using new and delete rather than malloc and free. – Mikel F Nov 28 '18 at 23:47
  • 1
    unrelated: `printf("The v size is: %d", v.size());` `size_t` doesn't match the %d specifier. You could get weird outputs. – user4581301 Nov 28 '18 at 23:49
  • 2
    In `vector v {3,2,4,5};`, `{3,2,4,5};` are not template parameters. That's an initializer list. – user4581301 Nov 28 '18 at 23:51
  • the placeholder works the problem is in "m_array = {a...};" and i want to use more raw than using new or delete. I'm old school ahaha – Emanuel Clur Nov 28 '18 at 23:53
  • 2
    @EmanuelClur: "*i want to use more raw than using new or delete.*" Then why are you using C++? – Nicol Bolas Nov 29 '18 at 14:39
  • @NicolBolas My only reason to use c++ instead of c is templates. Why? Because the newest standasts are a lexical sugar; I mean the use of smart pointers instead of raw pointers or use operators like "new" or "delete" is an action that only makes the languge more "anti dumb". – Emanuel Clur Nov 29 '18 at 20:33
  • 2
    @EmanuelClur: "*Because the newest standasts are a lexical sugar*" Except that they're not. They're *really* not. C++ is not "C with stuff". You cannot create a C++ object by allocating memory and poking at it through a pointer to that type. – Nicol Bolas Nov 29 '18 at 21:17
  • @NicolBolas In memory there's not an Foo object. e.g: struct Foo { float x, y; }; int main(){ Foo* f_ptr = (Foo*) malloc(sizeof(Foo)); // In memory 8 bytes (4 per float) } The only difference between use malloc instead of new operator is: new operator make malloc with the size of the all variables and after that call to constructor. There's no problem with use that semantic but you can see that makes more "ignorants" programmers. So whathever I want help, no make me angry aahaha – Emanuel Clur Nov 29 '18 at 22:42
  • 2
    @EmanuelClur: "*The only difference between use malloc instead of new operator is: new operator make malloc with the size of the all variables and after that call to constructor.*" Then you can show me the part of the ISO C++ standard that says that `malloc` creates objects. I'll give you a head start: [intro.object/1.](https://timsong-cpp.github.io/cppwp/n4659/intro.object#1) That describes all of the C++ constructs that create objects. Your code may "work", but as far as the standard is concerned, it has undefined behavior. `new` is not "anti-dumb"; it's an integral part of the language. – Nicol Bolas Nov 30 '18 at 00:02
  • @NicolBolas You rlly think that c++ is OOP?. I'd said that new is an operator like otherone. If you don't belive me then take a look to the sentence "void* operator new( ... )". If it's not enought look at the follow code: struct Foo { int x, y; }; int main() { Foo f{3,4}; int* f_ptr = &f.x; printf("%d",f_ptr[0]); } Why can I do that? Because in memory the types doesn't exists, for the memory Foo is only bytes. Tell me now where is your object? – Emanuel Clur Nov 30 '18 at 00:18
  • @EmanuelClur: "*Why can I do that?*" Because the standard *says* you can. `f.x` is an object of type `int`, so it has an address. You copy that address to `f_ptr`, so `f_ptr` points to that object (which is a subobject of `f`). And `f_ptr[0]` also valid; it access the pointer as though it were an array, which is perfectly legal so long as the index is 0. There's nothing invalid in that code. – Nicol Bolas Nov 30 '18 at 00:30
  • 2
    @EmanuelClur: "*I'd said that new is an operator like otherone.*" It isn't. `::operator new` is a regular function. The *syntax* `new(...) type` is special syntax for creating an object. It does so by calling `operator new` with the given parameters, then using the return value from that call as the memory to create the `type` object within. Calling `::operator new` directly does not create objects; it merely allocates memory. – Nicol Bolas Nov 30 '18 at 00:31
  • 1
    Your class violates [The Rule of Three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – Mooing Duck Nov 30 '18 at 00:36
  • @NicolBolas: "You cannot create a C++ object by allocating memory and poking at it through a pointer to that type." You... totally can though. I mean, I love C++ as much as the next guy, but the `new operator` in most compilers merely calls malloc, and then uses placement new on the pointer to construct the class. https://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new/8918942#8918942 – Mooing Duck Nov 30 '18 at 00:40
  • 1
    @MooingDuck: "*You... totally can though.*" Not as far as the *standard* is concerned. Try doing `vector *foo = (vector*)malloc(sizeof(foo));` and see if `foo->empty()` is true the way it ought to be for a newly created empty `vector`. – Nicol Bolas Nov 30 '18 at 00:43
  • @NicolBolas: Here it is, working, with no undefined behavior: http://coliru.stacked-crooked.com/a/121baacc7a573b1d See § 18.6.1.3 on placement new. Oh, I see the misunderstanding. I thought you meant we couldn't call placement new, but you're referring to skipping that step. – Mooing Duck Nov 30 '18 at 00:51

1 Answers1

1

Braced-init-lists ({} constructs) are used to initialize objects as part of their creation. And the member subobjects of a type are initialized before the constructor starts. You can use a braced-init-list to initialize a member subobject, but only as part of a member initializer list.

And even then, m_array is just a pointer. So you could use braced-init-lists to initialize a pointer from another pointer value. But you can't use it to initialize an array when you don't use proper array syntax to create the array.

If you are creating a true vector-like type, then you'll have to take a std::initializer_list<Type> and copy those elements into the array:

vector(std::initializer_list<type> il)
 : m_size{il.size()},
 : m_array{(type*)::operator new(il.size() * sizeof(type), std::align_val_t{alignof(type)})}
{
    auto ptr = m_array;
    //Warning: not exception safe.
    for(const type &t : il)
    {
        new(ptr) type{t};
        ++ptr;
    }
}

~vector()
{
    //Destroy in reverse order.
    for(int ix = ((int)size() - 1); ix >= 0; --ix)
        m_array[ix]->~type();

    ::operator delete(m_array, m_size * sizeof(type), std::align_val_t{alignof(type)});
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    Note that this isn't exception safe. You'll have to catch the exception, and destruct the constructed elements, then allow the exception to unwind. – Mooing Duck Nov 30 '18 at 00:43
  • Also, your destructor doesn't destruct the elements. Wait, what does the destructor do? I'm unfamiliar with that overload. It appears to leak `m_array` at least. – Mooing Duck Nov 30 '18 at 00:43
  • @MooingDuck: I fixed the destructor. But I'm not writing out the exception handling code. – Nicol Bolas Nov 30 '18 at 00:48
  • Thx but ... there's no way using variadic template? – Emanuel Clur Nov 30 '18 at 02:04
  • @EmanuelClur: You could, but that would require recursive template instantiation or using some metaprogramming library. Variadic templates are easy to work with when all you need to do is repeat an expression in sequence, but having to perform both a `new` *and* a pointer increment makes it much more difficult. – Nicol Bolas Nov 30 '18 at 02:56