Why can't I use list insted of array?

Feb 12, 2020 at 2:28am
I'm a beginner in C++ and I have a question
in array.
We can initialize an array like this:
 
  int arr[] = {0, 0, 4, -3, 7, 8, 2};

and use array for a parameter of a function like this:
 
  int doSomethingOnAnArray(int a[]);

but why can't I call a funtion like this:
1
2
3
4
5
6
7
int doSomethingOnAnArray(int a[]);
...
int main() {
...
doSomethingOnAnArray({1, 2, 3, 4, 5, 6});
...
}
Feb 12, 2020 at 2:53am
You just can't. Arrays have been around since C. It could have potentially have been a feature, but I guess the evolution of C and C++ demonstrated otherwise.

You can, however, use an std::array or std::vector in this way.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Example program
#include <iostream>
#include <array>
#include <vector>
using std::array;
using std::vector;

int doSomethingOnAnArray(const array<int, 10>& arr)
{
    int sum = 0;
    for (int i = 0; i < 10; i++)
        sum += arr[i];
    return sum;
}

int doSomethingOnAVector(const vector<int>& arr)
{
    int sum = 0;
    for (size_t i = 0; i < arr.size(); i++)
        sum += arr[i];
    return sum;
}

int main()
{
    std::cout << doSomethingOnAnArray( {1, 2 } ) << '\n'; // NOTE: Implicitly sets elements [2]+ to 0.
    std::cout << doSomethingOnAnArray( {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ) << '\n';

    //std::cout << doSomethingOnAnArray( {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } ) << '\n'; // ERROR: Too many elements

    std::cout << doSomethingOnAVector( {1, 2, 3 } ) << '\n';
    std::cout << doSomethingOnAVector( {1, 2, 3, 4, 5 } ) << '\n';
}


With templates, you can also do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Example program
#include <iostream>
#include <array>
using std::array;

template <int N>
int doSomethingOnAnArray(const array<int, N>& arr)
{
    int sum = 0;
    for (int i = 0; i < N; i++)
        sum += arr[i];
    return sum;
}

int main()
{
    std::cout << doSomethingOnAnArray<2>( { 1, 2 } ) << '\n'; // forms array<int, 2>
    std::cout << doSomethingOnAnArray<10>( { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ) << '\n'; // forms array<int, 10>
    std::cout << doSomethingOnAnArray<14>( { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } ) << '\n'; // forms array<int, 14>
}


PS: Almost forgot to mention, the feature you're referring to is called "initializer list" (not to be confused with constructor initialization lists).
Last edited on Feb 12, 2020 at 3:03am
Feb 12, 2020 at 7:42am
Oh, thanks. I got it.
Feb 12, 2020 at 8:39am
1
2
3
4
5
6
int doSomething( int* arr );

int main()
{
    std::cout << doSomething( { 1, 2 } ) << '\n';
}

 In function 'int main()':
error: cannot convert '<brace-enclosed initializer list>' to 'int*' for argument '1' to 'int doSomething(int*)'

The int* and int[] should be interchangeable an parameter list:
int doSomething( int[] arr );
error: expected ',' or '...' before 'arr'
 In function 'int main()':
error: cannot convert '<brace-enclosed initializer list>' to 'int*' for argument '1' to 'int doSomething(int*)'

Stating the size of array does not help either:
int doSomething( int[2] arr );
error: expected ',' or '...' before 'arr'
 In function 'int main()':
error: cannot convert '<brace-enclosed initializer list>' to 'int*' for argument '1' to 'int doSomething(int*)'


Whether we write int*, int[], or int[2], the compiler sees int*.
On the other hand, { 1, 2 } is a <brace-enclosed initializer list>.

One more try:
1
2
3
4
int main()
{
    int* arr = { 1, 2 };
}

 In function 'int main()':
3:23: error: scalar object 'arr' requires one element in initializer

Different words, but it still says: "How am I supposed to squeeze all that into one value?"


Your compiler does say what it thinks to be a problem. Some is just about syntax, some not.
Feb 12, 2020 at 11:46am
@keskiverto, but I can't do this either:
1
2
int *p = new int[2];
p = {1, 2};

This time p has enough space to contains two value.
Feb 12, 2020 at 11:54am
1
2
3
4
5
6
7
#include <iostream>

int main()
{
   int *arr = new int[2]{ 1, 2 };
   std::cout << arr[0] << ' ' << arr[1] << '\n';
}



or

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <vector>

int main()
{
   std::vector<int> arr(2);
   arr = { 1, 2 };
   std::cout << arr[0] << ' ' << arr[1] << '\n';
}
Last edited on Feb 12, 2020 at 12:00pm
Feb 12, 2020 at 11:59am
Er. That's good. But you didn't answer my question.(or is this also about syntax?)
Feb 12, 2020 at 12:06pm
MILLER XYL wrote:
But you didn't answer my question.(or is this also about syntax?)

You asked this question (albeit not of me):
@keskiverto, but I can't do this either:
int *p = new int[2];
p = {1, 2};
This time p has enough space to contains two value.

I attempted to answer it.



Your p is a pointer. You can't assign a pointer to an initialiser list. And the "initialiser" in initialiser list means precisely that.

Other standard arrays have a nasty tendency to decay to pointers, too.

c++ doesn't necessarily work like other languages.
Last edited on Feb 12, 2020 at 3:54pm
Feb 12, 2020 at 12:14pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>

int main()
{
   int *arr = new int[2]{ 1, 2 };    // OK

// int arr[2] = { 1, 2 };            // OK

// int arr[2]{ 1, 2 };               // OK

// std::vector<int> arr{ 1, 2 };     // OK

// std::vector<int> arr;             // |OK
// arr = { 1, 2 };                   // |

// int arr[2];                       // |Not OK
// arr = { 1, 2 };                   // | 

   std::cout << arr[0] << ' ' << arr[1] << '\n';
}
Feb 12, 2020 at 2:11pm
> why can't I call a function like this
> doSomethingOnAnArray({1, 2, 3, 4, 5, 6});

To create prvalue of an array type, we need to use a brace-initialized functional cast
https://en.cppreference.com/w/cpp/language/array#Array_rvalues

This is fine:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

using array_type = int[5] ;

void doSomethingOnAnArray( const array_type& arr )
{
    std::cout << "{ " ;
    for( int v : arr ) std::cout << v << ' ' ;
    std::cout << "}\n" ;
}

int main()
{
    // A single-word type name followed by a braced-init-list is a prvalue of the specified type ...
    // This is the only cast expression that can create an array prvalue.
    // https://en.cppreference.com/w/cpp/language/explicit_cast (5)
    doSomethingOnAnArray( array_type{ 1, 2, 3 } ) ;
}

http://coliru.stacked-crooked.com/a/5ce470072a3dc819
https://rextester.com/PYET59613
Feb 12, 2020 at 2:29pm
C-arrays are simple things.
They are nothing more than a pointer to a fixed size block of memory. They are NOT objects, and this is the 'why' behind it, they can't do what objects can do because they are not objects :)

The compiler 'could' be back coded to start supporting some of these ideas, but that is unlikely to happen. Arrays predate objects, in C, and predate the STL and modern ideas.

- you can't resize it
- you can't assign, compare, or use other operators on it 'for all elements'
- it has a fixed size at compile time
- you can't delete to resize it or delete in the middle and have it automatically scoot the data.
- it does not know its own size
- it does not have iterators
and so on.
All these things can be done with a vector (though delete in the middle takes a bit of hand waving, its still one line of code), so if you want an objectified array, you have one available, and it is usually recommended to use a vector so you CAN get these tools.
Last edited on Feb 12, 2020 at 2:32pm
Feb 12, 2020 at 2:41pm
jonnin, C-arrays are objects distinct from pointers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Example program
#include <iostream>
#include <typeinfo>

void pass_array(int(&arr)[10]) { }

int main()
{
    int arr[10];
    
    int* ptr =  arr;
    std::cout << typeid(arr).name() << '\n'
              << typeid(ptr).name() << '\n'
              << sizeof(arr) << '\n'
              << sizeof(ptr) << '\n';
    
    pass_array(arr);
    //pass_array(ptr); // error
}

A10_i  // "Array of 10 ints"
Pi    // "Pointer to int"
40
8

If it were just a pointer, then something like keskiverto's example would work
1
2
3
4
int main()
{
    int* arr = { 1, 2 };
}

Maybe I'm being pedantic but meh.
Last edited on Feb 12, 2020 at 2:47pm
Feb 12, 2020 at 3:30pm
I suppose it depends on how you define an object. Arrays are distinct from pointers (agreed!) but both are still just an address and an offset and are more alike than different. If you are coming from newer languages where 'arrays' in those languages are objects and are like what we call vectors, its critical to make a distinction. How pedantic you want to get on that is up to you :)
Last edited on Feb 12, 2020 at 3:31pm
Feb 12, 2020 at 4:15pm
An object of an array type is an object that contains sub-objects (array elements).
An object of an class type is an object that may contain sub-objects (member sub-objects and base class sub-objects).
Feb 13, 2020 at 1:21am
It's clear now. Thanks to you all!
Topic archived. No new replies allowed.