Initialize private array with unknown number of elements (C++98) - c++

Looks like I missed something fundamental here, but haven't worked it out.
Below is a snippet and its corresponding output.
What I wanted to do is:
- Declare and initialize an array of structs, without knowing the number of elements in advance.
- Ideally the array itself and its number of elements are private members.
What I tried:
Declared m_member_tab[] and m_num_members as private.
Created an Init() function that initializes m_member_tab[] and calculate m_num_members.
Outcome:
m_member_tab[] is initialized ok (see below output).
BUT inside the constructor (after calling Init), m_member_tab is corrupted.
#include <iostream>
using std::cout; using std::endl;
class TArrayTest
{
public:
TArrayTest();
private:
void Init();
typedef struct _TMember
{
int m_key;
int m_val;
}
TMember;
TMember m_member_tab[];
int m_num_members;
};
TArrayTest::TArrayTest()
{
Init();
cout << "Ctor: Number of elements = " << m_num_members << endl;
for( int i = 0; i < m_num_members; i++ )
{
cout << "Ctor: "
<< "key " << m_member_tab[i].m_key
<< " - val " << m_member_tab[i].m_val
<< endl;
}
};
void TArrayTest::Init()
{
TMember m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};
m_num_members = sizeof( m_member_tab ) / sizeof( TMember );
cout << "Init: Number of elements = " << m_num_members << endl;
for( int i = 0; i < m_num_members; i++ )
{
cout << "Init: "
<< "key " << m_member_tab[i].m_key
<< " - val " << m_member_tab[i].m_val
<< endl;
}
}
int main()
{
TArrayTest test;
}
Output:
Init: Number of elements = 5
Init: key 1 - val 100
Init: key 2 - val 200
Init: key 3 - val 300
Init: key 4 - val 400
Init: key 5 - val 500
Ctor: Number of elements = 5
Ctor: key 5 - val 32766
Ctor: key 0 - val 0
Ctor: key 0 - val 0
Ctor: key -1212526907 - val 32623
Ctor: key 0 - val 0

This member declaration:
TMember m_member_tab[];
is not valid C++.
There is an additional problem in the init function, where you declare a local variable of the same name, but it doesn't matter: the above declaration is not just invalid, but since it's not at the end of the struct it doesn't even make sense as a language extension.
Instead, use std::vector, like this:
std::vector<TMember> m_member_tab;
It keeps track of the array size, so you don't need that extra member.
In other news, C++ directly supports initialization of an instance of a class. You should not define ordinary function for that. Instead use the language mechanism for that, namely a constructor.
You can find information about constructors in any tutorial and any introductory C++ textbook.
The language supported mechanism has many advantages compared to an init function.
Oh, and seeing as each item in the array will contain a key and a value, do consider a std::map, or, if you can use C++11 and not just C++98/C03, std::unordered_map (faster but no sorted traversal of keys).

in the first line of void TArrayTest::Init():
TMember m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};
you declare "m_member_tab" a temporary variable, not Member variable. you should write like this:
m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};

The feature you are trying to use does not exist in C++ language. It is illegal to use [] in non-static member array declarations. It is allowed in static member array declarations, but non in non-static ones.
Even if your compiler somehow allows this declaration, it probably interprets it as a zero-sized array. The array size is fixed at that point - there's no way to somehow "intialize" it into a bigger array later.
Member array declaration with [] might be allowed by some compilers as a way to support C-style "struct hack". But that is a completely different technique.

Related

How to get value from a vector by value from another vector?

I have two vectors:
one contains numbers and names of things;
second collects numbers that have already been showed to the user;
I'm trying to make a history list of all objects that have been shown.
Here is my code:
class palettArchive{
private:
std::vector<std::pair<int,std::string>> paletts;
int palletsCounter;
std::vector<int> choosen;
public:
//...
void history(){
auto printHist = [](int& i){
int tmp = i;
std::pair<int,std::string> tempPair = paletts[tmp];
std::cout << tempPair.first << " " << tempPair.second;
return 0;
};
std::for_each(choosen.begin(), choosen.end(), printHist);
}
};
There is an error:
error: 'this' cannot be implicitly captured in this context
std::pair<int,std::string> tempPair = paletts[tmp];
I can't make a third vector with the list that is created already. I need to make it by calling a function and printing at the time.
The lambda must capture this to be able to access member variables:
auto printHist = [this](int& i){ ... };
for_each and lambda are just making your life difficult. The simpler code is explicit iteration:
void history()
{
for (auto i : choosen) {
auto tempPair = paletts[i];
std::cout << tempPair.first << " " << tempPair.second;
// did you mean to send a newline "\n" also?
}
}

Visual Studio 2019 does not handle aggregate initialization of dynamic array of structs correctly

The code below prints garbage (or zeroes) if compiled with VC++ 2017 and "1122" if compiled with GCC or Clang (https://rextester.com/JEV81255). Is it bug of VC++ or I'm missing something here?
#include <iostream>
struct Item {
int id;
int type;
};
int main()
{
auto items = new Item[2]
{
{ 1, 1 },
{ 2, 2 }
};
std::cout << items[0].id << items[0].type;
std::cout << items[1].id << items[1].type;
}
At the same time it works if elements are of a primitive type (like int).
I got it to work by writing the following but then the data is not stored on the Heap.
Item items[] {
{ 1, 1 },
{ 2, 2 }
};
If you need it on the heap use the solution below it seems to work with the vc++ compiler. (Note that this is only a workaround and does nt fix the underlying problem):
Item* Items[2];
Items[0] = new Item{3,3};
Items[1] = new Item{4,4};
std::cout << (*Items[0]).id << (*Items[0]).type << std::endl;
std::cout << (*Items[1]).id << (*Items[1]).type << std::endl;
Altenatively you can create the Array using the first option and then copy it into an Array on the heap like this:
Item items[2]{
{1,1},
{2,2}
};
Item* hitem = new Item[2];
for(int i = 0; i < 2; i++){
hitem[i].id = items[i].id + 4;
hitem[i].type = items[i].type + 4;
}
While this is slow it works like it is supposed to even on the vc++ compiler.
You can view the whole code here:https://rextester.com/VNJM26393
I don't know why it only works like this...

Which function should be preferred where the list of items could be about 100 and speed of lookup is important

Which version of ScreenID2Text is going to give me the best performance and code maintainability?
It cannot be assumed that the screen ID passed to the function is in the list. The real list will contain about 100 entries.
Or some other option. Edits to function most welcome.
#include <iostream>
#include <algorithm>
#include <map>
#include <unordered_map>
const char* ScreenID2Text1(const int ScreenID) {
static std::unordered_map<int, char*> screens = {
{ 1, "apple" },
{ 3, "banana" },
{ 4, "orange" },
{ 7, "date" } };
auto search = screens.find(ScreenID);
if (search != screens.end()) {
return search->second;
}
else {
return "unknown fruit";
}
}
const char* ScreenID2Text2(const int ScreenID) {
static std::map<int, char*> screens = {
{ 1, "apple" },
{ 3, "banana" },
{ 4, "orange" },
{ 7, "date" } };
auto search = screens.find(ScreenID);
if (search != screens.end()) {
return search->second;
}
else {
return "unknown fruit";
}
}
const char* ScreenID2Text3(const int ScreenID) {
struct screens {
int id;
const char* description;
};
static screens types[] = {
{ 1, "apple" },
{ 3, "banana" },
{ 4, "orange" },
{ 7, "date" } };
int size = sizeof(types) / sizeof(types[0]);
screens candidate;
candidate.id = ScreenID;
auto lower = std::lower_bound(&types[0], &types[0] + size, candidate,
[](const screens& lhs, const screens& rhs) { return lhs.id < rhs.id; });
if (lower != &types[0] + size && lower->id == ScreenID)
return lower->description;
else
return "unknown fruit";
}
int main() {
int tests[] = { 1,2,3 };
int numtests = sizeof(tests) / sizeof(tests[0]);
for (int i = 0; i < numtests; ++i) {
// unordered map
std::cout << "Test ID" << tests[i] << " result=" << ScreenID2Text1(tests[i]) << '\n';
// unordered map
std::cout << "Test ID" << tests[i] << " result=" << ScreenID2Text2(tests[i]) << '\n';
// lower_bound
std::cout << "Test ID" << tests[i] << " result=" << ScreenID2Text3(tests[i]) << '\n';
}
}
Well, probably the third one, just because you don't end up hitting the memory allocator. Building a map/unordered_map every single time you call the function is going to take up most of the time of the first two versions. But calling lower_bound is likewise silly, and is going to lead to overly branchy code.
Instead, have the compiler deal with optimizing this for you:
const char* ScreenID2TextN(const int ScreenID) {
switch(ScreenID)
{
case 1: return "apple";
case 3: return "banana";
case 4: return "orange";
case 7: return "date";
default: return "unknown fruit";
}
}
I would be extremely surprised if any of your versions beat this one.
If you know that the map is fixed and known at compile time you might consider a perfect hash approach, and use a generator like gperf.
Of course you'll better build the map (e.g. a std::map, or a std::unordered_map, or your own one) ahead of time (perhaps in your initialization routine).
In all cases, you need to benchmark. In most cases, for only a hundred entries, performance won't matter that much (since the data is likely to sit in some L1 or L2 cache).
In your MCVE example, you could even switch on the screen id (see Sneftel's answer)... And you might generate the C or C++ code of that switch...
Another approach (a bit silly, but could be made very efficient) might be to generate and JIT-compile some code based upon the map. You'll then use a JIT library like libgccjit to generate an efficient function from your map. Or generate some C or C++ code at runtime (perhaps using gperf for that) and compile it as a plugin then dlopen(3) it.
Or, as commented by Marc Glisse, use some vector. Most other approaches above could also fit if you need a fast, reverse, mapping (between names and ids).
PS. You really need to check that the speed of your ScreenID2Text function matters that much for the overall performance of your entire application (I guess it does not).

print Function for arrays - c++

I was working on a print() function in C++ and was wondering:
template <typename BaseType>
void print(BaseType data, bool newline = false, bool raw = false) {
// Standard > C Out
std::cout << data;
/* Logic
If
Newline is true.
*/
if (newline)
std::cout << std::endl;
};
What if this same function could react differently to arrays and print out each individual member of the array rather than give back a value like 0x22fe30?
Something like:
print("Hello, World!"); // prints "Hello, World!"
print(array); // prints "[1, 0, 1]"
I'm only doing this for fun to see how far my skills in C++ really are and would appreciate any helpful answer. Thanks.
You can iterate into array and print them out:
const int arr [ 3 ] = { 5, 6, 7 };
for ( int i = 0; i < 3; i++ )
std::cout << arr [ i ] << std::endl;

Check if element found in array c++

How can I check if my array has an element I'm looking for?
In Java, I would do something like this:
Foo someObject = new Foo(someParameter);
Foo foo;
//search through Foo[] arr
for(int i = 0; i < arr.length; i++){
if arr[i].equals(someObject)
foo = arr[i];
}
if (foo == null)
System.out.println("Not found!");
else
System.out.println("Found!");
But in C++ I don't think I'm allowed to search if an Object is null so what would be the C++ solution?
In C++ you would use std::find, and check if the resultant pointer points to the end of the range, like this:
Foo array[10];
... // Init the array here
Foo *foo = std::find(std::begin(array), std::end(array), someObject);
// When the element is not found, std::find returns the end of the range
if (foo != std::end(array)) {
cerr << "Found at position " << std::distance(array, foo) << endl;
} else {
cerr << "Not found" << endl;
}
You would just do the same thing, looping through the array to search for the term you want. Of course if it's a sorted array this would be much faster, so something similar to prehaps:
for(int i = 0; i < arraySize; i++){
if(array[i] == itemToFind){
break;
}
}
There are many ways...one is to use the std::find() algorithm, e.g.
#include <algorithm>
int myArray[] = { 3, 2, 1, 0, 1, 2, 3 };
size_t myArraySize = sizeof(myArray) / sizeof(int);
int *end = myArray + myArraySize;
// find the value 0:
int *result = std::find(myArray, end, 0);
if (result != end) {
// found value at "result" pointer location...
}
Here is a simple generic C++11 function contains which works for both arrays and containers:
using namespace std;
template<class C, typename T>
bool contains(C&& c, T e) { return find(begin(c), end(c), e) != end(c); };
Simple usage contains(arr, el) is somewhat similar to in keyword semantics in Python.
Here is a complete demo:
#include <algorithm>
#include <array>
#include <string>
#include <vector>
#include <iostream>
template<typename C, typename T>
bool contains(C&& c, T e) {
return std::find(std::begin(c), std::end(c), e) != std::end(c);
};
template<typename C, typename T>
void check(C&& c, T e) {
std::cout << e << (contains(c,e) ? "" : " not") << " found\n";
}
int main() {
int a[] = { 10, 15, 20 };
std::array<int, 3> b { 10, 10, 10 };
std::vector<int> v { 10, 20, 30 };
std::string s { "Hello, Stack Overflow" };
check(a, 10);
check(b, 15);
check(v, 20);
check(s, 'Z');
return 0;
}
Output:
10 found
15 not found
20 found
Z not found
One wants this to be done tersely.
Nothing makes code more unreadable then spending 10 lines to achieve something elementary.
In C++ (and other languages) we have all and any which help us to achieve terseness in this case. I want to check whether a function parameter is valid, meaning equal to one of a number of values.
Naively and wrongly, I would first write
if (!any_of({ DNS_TYPE_A, DNS_TYPE_MX }, wtype) return false;
a second attempt could be
if (!any_of({ DNS_TYPE_A, DNS_TYPE_MX }, [&wtype](const int elem) { return elem == wtype; })) return false;
Less incorrect, but looses some terseness.
However, this is still not correct because C++ insists in this case (and many others) that I specify both start and end iterators and cannot use the whole container as a default for both. So, in the end:
const vector validvalues{ DNS_TYPE_A, DNS_TYPE_MX };
if (!any_of(validvalues.cbegin(), validvalues.cend(), [&wtype](const int elem) { return elem == wtype; })) return false;
which sort of defeats the terseness, but I don't know a better alternative...
Thank you for not pointing out that in the case of 2 values I could just have just if ( || ). The best approach here (if possible) is to use a case structure with a default where not only the values are checked, but also the appropriate actions are done.
The default case can be used for signalling an invalid value.
You can use old C-style programming to do the job. This will require little knowledge about C++. Good for beginners.
For modern C++ language you usually accomplish this through lambda, function objects, ... or algorithm: find, find_if, any_of, for_each, or the new for (auto& v : container) { } syntax. find class algorithm takes more lines of code. You may also write you own template find function for your particular need.
Here is my sample code
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
using namespace std;
/**
* This is old C-like style. It is mostly gong from
* modern C++ programming. You can still use this
* since you need to know very little about C++.
* #param storeSize you have to know the size of store
* How many elements are in the array.
* #return the index of the element in the array,
* if not found return -1
*/
int in_array(const int store[], const int storeSize, const int query) {
for (size_t i=0; i<storeSize; ++i) {
if (store[i] == query) {
return i;
}
}
return -1;
}
void testfind() {
int iarr[] = { 3, 6, 8, 33, 77, 63, 7, 11 };
// for beginners, it is good to practice a looping method
int query = 7;
if (in_array(iarr, 8, query) != -1) {
cout << query << " is in the array\n";
}
// using vector or list, ... any container in C++
vector<int> vecint{ 3, 6, 8, 33, 77, 63, 7, 11 };
auto it=find(vecint.begin(), vecint.end(), query);
cout << "using find()\n";
if (it != vecint.end()) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
using namespace std::placeholders;
// here the query variable is bound to the `equal_to` function
// object (defined in std)
cout << "using any_of\n";
if (any_of(vecint.begin(), vecint.end(), bind(equal_to<int>(), _1, query))) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
// using lambda, here I am capturing the query variable
// into the lambda function
cout << "using any_of with lambda:\n";
if (any_of(vecint.begin(), vecint.end(),
[query](int val)->bool{ return val==query; })) {
cout << "found " << query << " in the container\n";
}
else {
cout << "your query: " << query << " is not inside the container\n";
}
}
int main(int argc, char* argv[]) {
testfind();
return 0;
}
Say this file is named 'testalgorithm.cpp'
you need to compile it with
g++ -std=c++11 -o testalgorithm testalgorithm.cpp
Hope this will help. Please update or add if I have made any mistake.
If you were originally looking for the answer to this question (int value in sorted (Ascending) int array), then you can use the following code that performs a binary search (fastest result):
static inline bool exists(int ints[], int size, int k) // array, array's size, searched value
{
if (size <= 0) // check that array size is not null or negative
return false;
// sort(ints, ints + size); // uncomment this line if array wasn't previously sorted
return (std::binary_search(ints, ints + size, k));
}
edit: Also works for unsorted int array if uncommenting sort.
You can do it in a beginners style by using control statements and loops..
#include <iostream>
using namespace std;
int main(){
int arr[] = {10,20,30,40,50}, toFind= 10, notFound = -1;
for(int i = 0; i<=sizeof(arr); i++){
if(arr[i] == toFind){
cout<< "Element is found at " <<i <<" index" <<endl;
return 0;
}
}
cout<<notFound<<endl;
}
C++ has NULL as well, often the same as 0 (pointer to address 0x00000000).
Do you use NULL or 0 (zero) for pointers in C++?
So in C++ that null check would be:
if (!foo)
cout << "not found";