Strange vector initialization issue - c++

I recently debugged a strange C++ problem, in which a newly declared vector somehow had a size of 477218589. Here's the context:
struct Triangle {
Point3 a,b,c;
Triangle(Point3 x, Point3 y, Point3 z) : a(x), b(y), c(z) {}
Vector3 flat_normal() { return (a-c)^(b-c); }
};
vector<Triangle> triangles;
Calling triangles.size() returns the value 477218589.
I 'fixed' the problem by changing struct Triangle to class Triangle, but I'm wondering why there's any difference. Should I have done that typedef struct Foo { ... } Foo; magic? If so, why would that help?
If it matters, I'm using g++-4.1.

This
#include <vector>
#include <iostream>
struct Point3 {};
struct Triangle {
Point3 a,b,c;
Triangle(Point3 x, Point3 y, Point3 z) : a(x), b(y), c(z) {}
};
int main()
{
std::vector<Triangle> triangles;
std::cout << triangles.size() << '\n';
return 0;
}
prints 0 for me. If it also does for you, then the problem is in parts of the code not included in this snippet. If it prints anything else, something is fishy with your compiler/std lib/setup.

There shouldn't be any difference between declaring Triangle as a struct or class - in C++, the difference between the two is that the default access specification of the members is public for struct and private for class, but that's it.
Is there anything more to Triangle that you didn't include?

Related

C++ Need to enable class member variables to access an std::vector of instances of another class

I am working on an API that is supposed to allow you to draw simple geometric shapes and calculate their elements. The project is based on the SFML library.
I have this class:
#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED
#include "stdafx.h"
#include "Helper.h"
class Point : public AbstractShape
{
public:
Point(float x, float y);
Vector getCoords();
sf::VertexArray getShape();
void setLabel(std::string label, int param);
private:
float m_x, m_y, m_R;
std::string m_label;
sf::VertexArray m_shape;
sf::Text m_labelObject;
};
#endif
It inherits from the abstract class AbstractShape, just like other similar classes Segment and Triangle. I need this to be able to add the different shapes to a single container to process them conveniently in one place later on.
In the main function, I declare the container, then create an instance of Point and then push_back it to the container:
std::vector<AbstractShape*> shapes;
Point* p1 = new Point(100, 50);
p1->setLabel("A", 4);
shapes.push_back(p1);
I think it would be better if the instance could add itself to the container when the instance is created. To do that, the Point class should be able to see container from within itself. What is the best way to achieve this while not introducing too much coupling to the Point class?
To add itself to the container, the Point needs to be coupled with the container. Coupling the two seems like a bad idea: why should the Point know anything about std::vector?
If you use this pattern often in your code, it's better to define a function to instantiate and add the point to a container:
template<typename T=std::vector<Point*>>
Point *makePoint(int x, int y, T container) {
Point *p = new Point(x, y);
container.push_back(p);
return p; // so we can set other properties easily
}
Or to create another Context class which encapsulates the set of points:
template <typename T=std::vector<Point*>>
class Context {
T container;
public:
Point* addPoint(int x, int y) {
Point *p = new Point(x, y);
container.push_back(p);
return p;
}
};
Also you may wish to use shared_ptr or unique_ptr to avoid memory leaks, though this may get a bit messy with inheritence.
Here's a fully WME on Ideone with the 2nd option:
#include <iostream>
#include <vector>
using namespace std;
class Point {
public:
Point (int x, int y) {}
};
template <typename T=std::vector<Point*>>
class Context {
T container;
public:
Point* addPoint(int x, int y) {
Point *p = new Point(x, y);
container.push_back(p);
return p;
}
};
int main() {
Context<> c;
c.addPoint(1, 2);
return 0;
}
I think it would be better if the instance could add itself to the
container when the instance is created.
This is your decision, but think twice on it - in most situations it is better to keep objects as simple as possible. If you need just to simplify your code, this can be made:
You can make external construction function, similar to std::make_share and std::make_tuple:
This will make you able to call:
construct<Point>(container, 1, 2);
construct<Line>(container, 1, 2, 3, 4);
And it will construct Point/Line and put into container in one line
Full code:
#include <iostream>
#include <vector>
using namespace std;
struct AbstractShape
{
virtual std::ostream& dump(std::ostream&) = 0;
};
struct Point : AbstractShape
{
Point(float x, float y) : x(x), y(y) {}
virtual std::ostream& dump(std::ostream& o) override
{
return o << "P[" << x << ":" << y << "]";
}
float x, y;
};
struct Line : AbstractShape
{
Line(float x1, float y1, float x2, float y2) : x1(x1), y1(y1), x2(x2), y2(y2) {}
virtual std::ostream& dump(std::ostream& o) override
{
return o << "L[" << x1 << ":" << y1 << "," << x2 << ":" << y2<< "]";
}
float x1, y1, x2, y2;
};
template<typename Object, typename Container, typename ...Args>
Object* construct(Container& c, Args... args)
{
Object* res = new Object(args...);
c.push_back(res);
return res;
}
int main() {
std::vector<AbstractShape*> container;
construct<Point>(container, 1, 2);
construct<Line>(container, 1, 2, 3, 4);
for (auto s : container)
s->dump(std::cout) << std::endl;
return 0;
}
Output:
P[1:2]
L[1:2,3:4]
Live test
And I definitely recommend using std::unique_ptr instead of raw pointers

What workaround can I use for compile error C2797 in the following C++ code?

I've been using Visual Studio 2013 after update 3 and am getting error C2797, "List initialization inside member initializer list or non-static data member initializer is not implemented", see https://msdn.microsoft.com/en-us/library/dn793970.aspx. I want to use a workaround in the following C++ code but I just can't figure out or find out what it should be. Could you please give me a suggestion?
This is where I believe I need the workaround
class Shape { // deals with color and style, and holds sequence of lines
protected:
Shape{initializer_list<Point> lst}; // add() the Points to this Shape
and a Point is
#ifndef POINT_GUARD
#define POINT_GUARD
typedef void (*Callback)(void*,void*);
namespace Graph_lib {
struct Point {
int x,y;
Point(int xx, int yy) : x(xx), y(yy) { }
Point() :x(0), y(0) { }
Point& operator+=(Point d) { x+=d.x; y+=d.y; return *this; }
};
inline bool operator==(Point a, Point b) { return a.x==b.x && a.y==b.y; }
inline bool operator!=(Point a, Point b) { return !(a==b); }
}
#endif
Many thanks for the help.
A constructor is defied with parentheses not curly braces.
Shape{initializer_list<Point> lst};
Becomes
Shape(initializer_list<Point> lst);
Then you can use curly braces to make an object like:
Shape shape{point1, point2, point3 };

What is the scope of a class inside of a class in C++?

I've written a class that looks like
class Mesh {
public:
vector<Vertex> vs;
}
where Vertex is
class Vertex {
public:
const double x, y, z;
}
I have a function which loads a Mesh from a file:
shared_ptr<Mesh> load_mesh(string filename) {
//....
vector<Vertex> vs;
Vertex v(1, 2, 3);
vs.push_back(v);
return shared_ptr<Mesh>(Mesh(vs));
}
My questions are concerning the scope of the Vertex and the vector.
Will one or both go out of scope?
Which (if any) of the alternatives are preferred?
class Mesh1 {
public:
vector<shared_ptr<Vertex>> vs;
}
class Mesh2 {
public:
shared_ptr<vector<Vertex>> vs;
}
class Mesh3 {
public:
shared_ptr<vector<shared_ptr<Vertex>>> vs;
}
Or is there a better / easier way of handling this?
Your basic structure looks right to me. You are copying the Vertex into the vector and then copying the vector into the Mesh. The local copies in the load_mesh() function will go out of scope but because you have made a copy that is ok.
At the risk of being accused of premature optimization I would say that unless the vector is small all that copying is a little inefficient. There are a number of ways it could be optimized. With C++11, and move semantics, you can keep your current structure and just move the data:
#include <vector>
struct Vertex {
const double x, y, z;
Vertex(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {}
};
struct Mesh {
std::vector<Vertex> vs;
Mesh(std::vector<Vertex> _vs) : vs(std::move(_vs)) {}
Mesh(Mesh&& other) noexcept : vs(std::move(other.vs)) {} // Move constructor
};
Mesh
loadMesh() {
//....
std::vector<Vertex> vs;
vs.emplace_back(1,2,3);
return Mesh{std::move(vs)};
}
int main() {
auto mesh = loadMesh();
}
I'm using emplace_back instead of push_back to construct the Vertex in the vector in-place and using std::move to move the vector into Mesh.
Returning a shared_ptr<Mesh> would be fine but I wanted to show you can also return the Mesh by value. The compiler should perform RVO and there will be no copy (see this question).

No appropriate default constructor available in struct with glm vectors

in .h:
enum collisionType {AB, BA, AoverB, AunderB};
struct Collision {
public:
collisionType type;
glm::vec2 point1;
glm::vec2 point2;
Collision(enum collisionType, glm::vec2, glm::vec2);
};
in .cpp:
Collision::Collision(enum collisionType collisType, glm::vec2 p1, glm::vec2 p2) : type(collisType), point1(p1), point2(p2)
{
}
using it
std::vector<Collision> collisions;
glm::vec2 point1(11.0, 12.0);
glm::vec2 point2(12.0, 13.0);
collisions.push_back(Collision(AoverB, point1, point2));
Getting error C2512: 'Collision' : no appropriate default constructor available, why?
You can read here the requirements for a type T to be well suited for std::vector.
Default-constructible is not listed there.
I also tried compiling this minimal code sample, in which X doesn't have a default constructor, and it compiles fine with MSVC:
#include <vector>
struct X {
X(int a, int b) : A(a), B(b) {}
int A;
int B;
};
int main() {
std::vector<X> v;
v.push_back(X(10,20));
}
So, the problem must be elsewhere in your code.
Anyway, you may want to add a constructor with no arguments to make your Collission class "default-constructible", and make the compiler happy:
struct Collision {
// Default constructor.
// Initialize data members to some init values.
Collision() {
...
}
PS Note that struct in C++ is equivalent to class { public: ..., so you can omit the public: line in your code: it's implied by the use of the keyword struct.
The following code compiles fine, it's something else that is the problem.
#include <glm/vec2.hpp>
#include <vector>
enum collisionType {AB, BA, AoverB, AunderB};
struct Collision {
public:
collisionType type;
glm::vec2 point1;
glm::vec2 point2;
Collision(enum collisionType, glm::vec2, glm::vec2);
};
Collision::Collision(enum collisionType collisType, glm::vec2 p1, glm::vec2 p2) : type(collisType), point1(p1), point2(p2)
{
}
int main()
{
std::vector<Collision> collisions;
glm::vec2 point1(11.0, 12.0);
glm::vec2 point2(12.0, 13.0);
collisions.push_back(Collision(AoverB, point1, point2));
}

How can i extend a class in a library like Armadillo?

I'm working with 3D vectors for 3d Graphics.
I created a class vec3 to add functions like getX, getY, getZ, setX, setY, setZ, setXYZ... and so on.
#include <armadillo>
using namespace arma;
// An extension to VEC class for Armadillo for 3D graphics.
class vec3 : public vec
{
public:
// Constructor inits vector to 0,0,0
vec3() : vec(3,fill::zeros) {}
~vec3(void){};
double getX() const { return at(0); }
double getY() const { return at(1); }
double getZ() const { return at(2); }
void setX(double x){ ?????? = x; }
};
I found myself lost in a very unusual situation i never found:
How do i use (i) access to elements... inside the class?
For the getter function, as you can see, it is easy since we have an "at" function, at least.
But how do i create a setX function, that inserts in the 0 position of the vector the given element...
I tried this(i) , obviously didn't work. I feel so newbie here...
Where is "vec" built over?. A std::vector?... Am i doing right by doing this simple stuff?
at(0) = x; should work if vec is derived from std::vector because at function can return non-constant reference.