This question already has an answer here:
How can I declare a member vector of the same class?
(1 answer)
Closed 5 years ago.
Why is the following code valid? The struct test contains a vector of test, so that the following code compiles (IDEOne):
#include <iostream>
#include <vector>
using namespace std;
struct test {
vector<test> a;
};
int main() {
// your code goes here
test t;
if (t.a.size() > 0)
return -1;
else if (t.a[0].a[0].a.size() > 0)
return 1;
return 0;
}
How does the compiler handle the struct so that is is possible to test for t.a[0].a[0].a.size()? Is there a limit on how often I could repeat the .a[0]?
Edit: This questions has an answer that claims this is undefined behaviour: Are C++ recursive type definitions possible, in particular can I put a vector<T> within the definition of T?
=> This is confusing
=> perhaps my question is a duplicate
This boils down to vector<T> not needing to know the size a value of type T occupies, which allows T to be an incomplete type. Essentially, the mechanism in play here is the same as in this declaration:
struct test {
test* start;
test* end;
};
The compiler has no problem declaring pointers to any type, as long as you promise to define it at some later point.
This behavior changes based on the template: you have no problem defining test with a vector<T>, but an array<T,Size> or even a pair<T,K> would be problematic:
struct broken1 {
array<broken1,3> a; // Does not compile
};
struct broken2 {
pair<broken2,broken2> p; // Does not compile
};
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Let's say you have some older code and data structures:
struct TEST
{
int a;
int b;
};
TEST *items[9]; // Points to an array of TEST*
Now I want to sort these objects. Old code uses QSort, but I want to use std::sort. What would this look like?
I tried something like:
typedef std::function<bool(const TEST *, const TEST*)> TestCompareType;
TEST **items;
std::sort(items, items+size,
[](const TEST *p1, const TEST *p2)
{
if(p1->a == p2->a)
{
return p1->b < p2->b;
}
else
{
// Ooops! Forgot to put "return here"
p1->a < p2->a;
// This would fix it
// return p1->a < p2->a;
}
});
but I get a crash saying "Expression: invalid comparator"
Any ideas?
Update: I was completely off base about thinking the error had something to do with using std::sort with arrays of pointers. I replaced the example code with code that was closer to what I had. Figured out that I had a typo. I didn't have a return in all cases of the comparator.
When you use
struct
{
int a;
int b;
} TEST;
You are defining TEST to be a variable of an anonymous struct type.
And then you proceed to use TEST as though it were a type.
TEST **items;
Change the definition of TEST so it is a type.
struct TEST
{
int a;
int b;
};
Here's a demonstrative program that builds successfully but does not do anything useful.
#include <algorithm>
#include <cstddef>
struct TEST
{
int a;
int b;
};
void sortStuff(TEST** items, size_t size)
{
std::sort(items, items+size,
[](const TEST *p1, const TEST *p2) { return p1->a < p2->a; });
}
int main() {}
I have a header file like the below -
// abc.hpp
#include <vector>
#include <string>
namespace A
{
namespace B
{
struct abc
{
std::string _type;
};
using abc_vector = std::vector<abc>;
}
}
I am using forward declaration in another header file.
// con.hpp
#include <vector>
namespace A
{
namespace B
{
struct abc; // Forward Declaration
using abc_vector = std::vector<abc>;
}
namespace C
{
class N
{
public:
B::abc_vector foo(std::string type);
};
}
}
What really confuses me is that my code compiles and works.
How is the vector allowed to be declared with incomplete type?
I think that it shouldn't be able to decide the size of abc.
using abc_vector = std::vector<abc>;
The below is the code I used to test my header files.
Strange enough, that it compiles and works all fine.
#include "con.hpp"
#include "abc.hpp"
#include <iostream>
namespace A
{
namespace C
{
B::abc_vector N::foo(std::string type)
{
B::abc a;
a._type = type;
B::abc_vector d;
d.push_back(a);
return d;
}
}
}
int main()
{
A::C::N n;
auto container = n.foo("test");
for (const auto& i : container)
std::cout << i._type << ' ';
return 0;
}
The code line
using abc_vector = std::vector<abc>;
only introduces a type alias for std::vector<abc>. That doesn't require, by any means, the size of abc since no object of type abc is allocated at all. Only a new type is declared.
B::abc_vector d;
Indeed needs the definition of abc. Nevertheless it works because at this point abc already has been defined because the header file abc.hpp has been included.
You are referring to this answer, where
std::vector<B> v;
is "done." This is not the same as what you did. You just introduced a type alias. std::vector<B> v; actually defines a variable. Therefore the definition of B is mandatory.
Note that
using abc_vector = std::vector<abc>;
is equivalent to
typedef std::vector<abc> abc_vector;
Maybe this makes it a bit clearer why the size of abc isn't necessary to know at this time point in compilation.
This is an interesting topic (at least to me) and applies to other std containers.
Originally the standard made it undefined behaviour to instantiate a container of an incomplete type. However implementations did not disallow it. This was in all likelihood not deliberate, but merely a side-effect of the fact that elements in (for example the vector) are stored in a memory location that is referenced by a pointer.
Thus the size of an element does not need to be known until an element is actually required - during the instantiation of a member function of the vector.
Here is a starting point for research if you'd like to explore further:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html
There is an interesting observation. Both GCC5.2 and CLANG3.6 compile following code.
struct A;
std::vector<A> my_func(); //Definition of my_func is in some CPP file
But throw errors for
struct A;
std::vector<A> v;
And reasoning for this is size of vector won't change for different type it is holding. See following code snippet.
struct B{int i; int j;};
struct C{int a,b,c;};
std::vector<B> pp;
std::vector<C> qq;
int main()
{
std::cout<<sizeof(pp)<<'\n';
std::cout<<sizeof(qq)<<'\n';
}
Output
24
24
But for std::vector<A> v it has to provide the Allocator<A>() as well. And allocator required members of struct A like constructor, copy constructor, destructor etc.
Also one important thing to note here is pointer arithmetic for incomplete type is not allowed.
If you see the errors thrown by CLANG, it clearly says same.
In file included from /tmp/gcc-explorer-compiler115920-68-1xsb8x7/example.cpp:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/vector:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:161:9: error: arithmetic on a pointer to an incomplete type 'A'
- this->_M_impl._M_start); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:253:7: note: in instantiation of member function 'std::_Vector_base<A, std::allocator<A> >::~_Vector_base' requested here
vector()
^
Everything else is quite straight forward.
Following is a typedef , so compiler does need to know about size.
using abc_vector = std::vector<abc>;
So, the code structure discussed in question is good to go ahead with.
I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);
I'm looking to the answer to the following question: is may_alias suitable as attribute for pointer to an object of some class Foo? Or must it be used at class level only?
Consider the following code(it is based on a real-world example which is more complex):
#include <iostream>
using namespace std;
#define alias_hack __attribute__((__may_alias__))
template <typename T>
class Foo
{
private:
/*alias_hack*/ char Data[sizeof (T)];
public:
/*alias_hack*/ T& GetT()
{
return *((/*alias_hack*/ T*)Data);
}
};
struct Bar
{
int Baz;
Bar(int baz)
: Baz(baz)
{}
} /*alias_hack*/; // <- uncommeting this line apparently solves the problem, but does so on class-level(rather than pointer-level)
// uncommenting previous alias_hack's doesn't help
int main()
{
Foo<Bar> foo;
foo.GetT().Baz = 42;
cout << foo.GetT().Baz << endl;
}
Is there any way to tell gcc that single pointer may_alias some another?
BTW, please note that gcc detection mechanism of such problem is imperfect, so it is very easy to just make this warning go away without actually solving the problem.
Consider the following snippet of code:
#include <iostream>
using namespace std;
int main()
{
long i = 42;
long* iptr = &i;
//(*(short*)&i) = 3; // with warning
//(*(short*)iptr) = 3; // without warning
cout << i << endl;
}
Uncomment one of the lines to see the difference in compiler output.
Simple answer - sorry, no.
__attrbite__ gives instructions to the compiler. Objects exist in the memory of the executed program. Hence nothing in __attribute__ list can relate to the run-time execution.
Dimitar is correct. may_alias is a type attribute. It can only apply to a type, not an instance of the type. What you'd like is what gcc calls a "variable attribute". It would not be easy to disable optimizations for one specific pointer. What would the compiler do if you call a function with this pointer? The function is potentially already compiled and will behave based on the type passed to the function, not based on the address store in the pointer (you should see now why this is a type attribute)
Now depending on your code something like that might work:
#define define_may_alias_type(X) class X ## _may alias : public X { } attribute ((may_alias));
You'd just pass your pointer as Foo_may_alias * (instead of Foo *) when it might alias. That's hacky though
Wrt your question about the warning, it's because -Wall defaults to -Wstrict-aliasing=3 which is not 100% accurate. Actually, -Wstrict-aliasing is never 100% accurate but depending on the level you'll get more or less false negatives (and false positives). If you pass -Wstrict-aliasing=1 to gcc, you'll see a warning for both
My declaration is as follows
#include <vector>
#include <iostream>
using namespace std;
typedef struct _ListofHops_T
{
int macAddrLtr;
int ttlValue;
}ListofHops;
struct ReadActivateLinkTrace
{
typedef std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
int main()
{
ReadActivateLinkTrace readLinkTrace;
for (size_t listItr=0; listItr < readLinkTrace.ListofHopsList.size(); listItr++)
{
.....
}
}
I am trying to declare a vector of list of hops struct within a struct ReadActivateLinkTrace.
Is the above declaration valid.
I get the following error compiling
vector.cpp:23: error: invalid use of
ReadActivateLinkTrace::ListofHopsList
I am new to vectors . how can i acess/iterate through vector of structures defined in a structure?
The declaration is valid, but it doesn't do what you think. ListofHopsList is a type (hint: typedef), not a variable. You're probably looking for
struct ReadActivateLinkTrace
{
std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
The problem wasn't with the vector itself, but with the fact that you weren't declaring a member, but defining a new type.
Also, is there any reason you're using a vector of pointers as opposed to a vector of objects?
ReadActivateLinkTrace::ListofHopsList is a typedef, which only declares an alias for a name of a type. It does not define an actual object of that type. You apparently want:
struct ReadActivateLinkTrace
{
std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
You should probably have some second thoughts about that being a vector of pointers though. At least offhand, it doesn't seem very likely that a pointer is the best choice here. While you're at it, this:
typedef struct _ListofHops_T
{
int macAddrLtr;
int ttlValue;
}ListofHops;
Is pretty horrible in a couple of ways. First the typedef here is only needed in C code, not C++. Second, the name _ListofHops_T is reserved for the implementation, so using it gives undefined behavior. This should be just:
struct ListofHops {
int macAddrLtr;
int ttlValue;
};