Juroza
Juroza

Reputation: 27

C++: How to pass array into an instance of a class and get the sizeof() it?

I want to pass an array into an instance of a class to be used within it. However, I can't get sizeof() the array. I get the warning "Sizeof on array function parameter will return size of 'float *' instead of 'float []'. "

int main() {
float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
Store test(info);
test.showArrayContents();
{

Class I want to pass array to

class Store{
float array[]; 
public:
Store(float temp[]){
    std::cout<<"\n"<<sizeof(temp); //can't get sizeof 
    for(int i=0;i<9;i++){
        array[i]=temp[i];
    };
}
void showArrayContents(){
   for(int i=0;i<9;i++){
       std::cout<<array[i];
    }
 }
};

How can I fix to get sizeof() correctly?

EDIT: I'm not trying to find how many elements are in the array but the amount of memory it takes up, which should be 40 bytes.

Upvotes: 1

Views: 510

Answers (4)

francesco
francesco

Reputation: 7539

For a static C-style array it is possible to infer its size using the expression

sizeof(info) / sizeof(*info)

This is also commonly implemented via a macro ARRAY_SIZE. Beware however that in the above code there is no check that the actual array is a static one.

Conversely, for a dynamically allocated C-style array, there is no possibility to infer its size, since the variable itself is nothing but a pointer.

In the class constructor, even if you knew the size of the array (for instance by passing the size as parameter), or if you assume that only a static array is used (and you employ the code above to infer its size), your code has a serious bug here:

for(int i=0;i<9;i++){
    array[i]=temp[i];
};

You are copying the elements of temp into array, but did you reserve memory for that? Again, array is merely a pointer to float, and if you do not explicitly allocate memory, in the above code you are writing into a part of memory which does not pertain to array. Hence you have UB.

If you know at compile time the size of the array, the right type to use is std::array. For instance

std::array<float, 10> info = {1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};

And then you can pass it to the class with something like

class Store{
std::array<float, 10> array;
public:
Store(std::array<float, 10> temp) : array{temp} { }

...

With a std::array you can always know its size with std::array::size.

Upvotes: 2

Bob__
Bob__

Reputation: 12759

I want to pass an array into an instance of a class to be used within it.

Ok, there are several ways to do that, I'll show you some of those later.

However, I can't get sizeof() the array.

You can't get it inside the function, after the array decayed to a pointer.

Store(float temp[]){
//          ^^^^^^    This is a pointer to float, not an array
}

Other than explicitly passing the size as a function argument, you could pass a reference to an array, using a template parameter to store the size (1).

#include <vector>
#include <iostream>

class Store
{
    std::vector<float> values_;
public:
    template< std::size_t N >
    Store(float const (&temp)[N]) : values_{temp, temp + N}
    {}//              ^^^^^^^^^^
 
    void showArrayContents() const noexcept
    {
        for(auto i : values_)
        {
            std::cout << ' ' << i;
        }
        std::cout << '\n';
    }
};

int main()
{
    float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    
    Store test(info);
    test.showArrayContents();
}

Get rid of the source array and use a std::initializer_list (2).

#include <vector>
#include <iostream>
#include <initializer_list>

class Store
{
    std::vector<float> values_; 
public:
    Store(std::initializer_list<float> src) : values_{src}
    {}
 
    //...
};

int main()
{
    Store test{1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    test.showArrayContents();
}

If the size never has to change during the lifetime of Store, you can use a std::array (3).

#include <algorithm>
#include <array>
#include <iostream>

template< class T, std::size_t N >
class Store
{
    std::array<T, N> values_; 
public:
    Store(T const (&src)[N]) 
    {
        std::copy(src, src + N, values_.begin());
    }
 
    //...
};

//deduction guide
template<class T, std::size_t N> Store( T (&src)[N] ) -> Store<T, N>;

int main()
{
    float info[]={1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    
    Store test(info);
    test.showArrayContents();
}

You can also avoid the source array and initialize the class with a constructor accepting a template parameter pack (4).

#include <algorithm>
#include <array>
#include <iostream>
#include <type_traits>

template< class T, std::size_t N >
class Store
{
    std::array<T, N> values_; 
public:
    template< class... Args >
    Store(Args... args) : values_{args...}
    {}
 
    //...
};

//deduction guide
template< class... Args >
Store(Args &&... ) -> Store<std::common_type_t<Args...>, sizeof...(Args)>;

int main()
{
    Store test{1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};
    test.showArrayContents();
}

Upvotes: 3

Eljay
Eljay

Reputation: 5321

How can I fix to get sizeof() correctly?

Option #1: you could pass in the size of the array.

#include <array>
#include <cstddef>
#include <iostream>

using std::cout;
using std::size;
using std::size_t;

namespace {

class Store {
    size_t array_size;
    float* array;
public:
    ~Store() {
        delete[] array;
    }
    Store(float temp[], size_t temp_size) : array_size{temp_size} {
        cout << "temp_size:" << temp_size << "\n";
        array = new float[temp_size];
        for (size_t i = 0; i < temp_size; ++i) {
            array[i] = temp[i];
        }
    }
    Store(Store const&) = delete;
    auto operator=(Store const&) -> Store& = delete;
    void showArrayContents() {
        auto sep = "";
        for (size_t i = 0; i < array_size; ++i) {
            cout << sep << array[i];
            sep = " ";
        }
        cout << "\n";
    }
};

} // anon

int main() {
    float info[] = { 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    Store test(info, size(info));
    test.showArrayContents();
}

Option #2: you could use a template constructor for the array.

#include <cstddef>
#include <iostream>

using std::cout;
using std::size_t;

namespace {

class Store {
    size_t array_size;
    float* array;
public:
    ~Store() {
        delete[] array;
    }
    template <size_t N>
    Store(float (&temp)[N]) : array_size{N} {
        cout << "N:" << N << "\n";
        array = new float[N];
        for (size_t i = 0; i < N; ++i) {
            array[i] = temp[i];
        }
    }
    Store(Store const&) = delete;
    auto operator=(Store const&) -> Store& = delete;
    void showArrayContents() {
        auto sep = "";
        for (size_t i = 0; i < array_size; ++i) {
            cout << sep << array[i];
            sep = " ";
        }
        cout << "\n";
    }
};

} // anon

int main() {
    float info[] = { 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    Store test(info);
    test.showArrayContents();
}

Option #3 (best option): you could use std::vector.

#include <cstddef>
#include <iostream>
#include <vector>
#include <utility>

using std::cout;
using std::move;
using std::ostream;
using std::size_t;
using std::vector;

namespace {

class Store {
    vector<float> array;
public:
    Store(vector<float> temp) : array{move(temp)} {
        cout << "temp size:" << temp.size() << "\n";
    }
    void showArrayContents(ostream& out) const {
        auto sep = "";
        for (auto&& e : array) {
            out << sep << e;
            sep = " ";
        }
        out << "\n";
    }
};

} // anon

int main() {
    auto info = vector<float>{ 1.0f, 2.3f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 67.8f };
    auto test = Store{info};
    test.showArrayContents(cout);
}

Upvotes: 1

hessam hedieh
hessam hedieh

Reputation: 820

You should pass the array length as an argument also, when you pass an array to function what you actually pass is a pointer to start location of array i.e. float* in your case, so when you ask for size it simply gives you size of pointer . So either pass the size explicitly, or use std::vector which will give you the length.

other than that if class Store is the owner of array, why not define it inside class?

Upvotes: 0

Related Questions