I am trying to create a void pointer to a class object and have it be initialized inside a function. Unfortunately, the array member of the class cannot escape the function i.e. it cannot be accessed after initialization.
In the code below, the first call to print positions (inside the initialize function) works properly, however, the second call to print positions from outside the initialization function fails. I have a feeling that the array object created in the initialization function is destroyed and not passed along but I am not sure and also don't know how to fix it.
Any help would be greatly appreciated.
#include <iostream>
#include <iomanip>
#include <string>
class Atoms
{
double * positions;
int nAtoms;
public:
// Standard constructor prividing a pre-existant array
Atoms(int nAtoms, double * positionsArray)
{
this->nAtoms = nAtoms;
this->positions = positionsArray;
}
// Print positions to screen
void print_positions()
{
std::cout<< "nAtoms: " << this->nAtoms << std::endl;
int nDim = 3;
for (int i = 0; i < nAtoms; i++)
{
for (int j = 0; j < nDim; j++)
{
std::cout << std::setw(6) << this->positions[i * nDim + j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
void initialize_Atoms_void_pointer(void ** voidAtomsPointer)
{
//Create a new instance of Atoms by a pointer
int numAtoms = 5;
int numDim = 3;
int elemN = numAtoms * numDim;
double data_array[elemN];
for (int i = 0; i < numAtoms; i++)
for (int j = 0; j < numDim; j++)
{
data_array[i * numDim + j] = i * numDim + j + 10;
}
Atoms *atoms = new Atoms(numAtoms, data_array);
// Set the vPointer that the void pointer points to a pointer to Atoms object
*voidAtomsPointer = static_cast<void *>(atoms);
//Test call
std::cout << std::endl << "Initializing atoms" << std::endl;
static_cast<Atoms *>(*voidAtomsPointer)->print_positions();
}
void print_Atoms_pointer_positions(void * voidAtomsPointer)
{
//Cast the pointer as an atoms pointer
Atoms *atomsPointer = static_cast<Atoms *>(voidAtomsPointer);
atomsPointer->print_positions();
}
int main()
{
//Use the initializer function for getting a pointer
void *testVoidAtomsPointer;
initialize_Atoms_void_pointer(&testVoidAtomsPointer);
print_Atoms_pointer_positions(testVoidAtomsPointer);
}
The problem is that in
Atoms *atoms = new Atoms(numAtoms, data_array);
data_array is a local array, which is destroyed when initialize_Atoms_void_pointer quits.
Instead of copying the raw pointer, make a new allocation in Atoms's constructor and copy the content:
Atoms(int nAtoms, double * positionsArray)
{
this->nAtoms = nAtoms;
this->positions = new double[nAtoms];
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
~Atoms()
{
delete[] this->positions;
}
A safer implementation would include the use of a std::unique_ptr, which will automatically de-allocate the memory for you when Atoms is destroyed:
#include <memory>
class Atoms {
std::unique_ptr<double[]> positions;
// ...
public:
Atoms(int nAtoms, double * positionsArray) :
positions(new double[nAtoms]) {
this->nAtoms = nAtoms;
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
// ...
};
You'd need also to check if nAtoms is 0 or negative, if the input array is null, etc., but I think it falls out of the scope of the question.
If you need to access the raw pointer, you can use the positions.get() method (do not try to delete it or your application will crash due to a double delete).
Update
Of course, another more straightforward solution is simply to use a std::vector<double> instead ;)
#include <vector>
class Atoms {
std::vector<double> positions;
// int nAtoms; -- no longer necessary
public:
Atoms(int nAtoms, double * positionsArray) :
positions(nAtoms) {
for (int ii = 0; ii < nAtoms; ++ii)
this->positions[ii] = positionsArray[ii];
}
// ...
};
If you need to access the raw pointer, you can use the positions.data() method (do not try to delete it or your application will crash due to a double delete). The number of atoms can be checked using positions.size().
As mentioned in a comment, if the only purpose of the Atoms class is to store doubles but not to add any other operation, then just forget about it and directly use the std::vector<double>.
Related
I'm working on graph implementations in C++ and came across an implementation for an adjacency matrix that mostly made sense to me. The implementation uses an "init" function to initialize the matrix:
void init(int n) {
numVertex = 0;
numEdge = 0;
mark = new int[n]; //initialize mark array
for (int i = 0; i < numVertex; i++) {
mark[i] = 0;
}
matrix = (int**) new int*[numVertex]; //make matrix
for (int i = 0; i < numVertex; i++) {
matrix[i] = new int[numVertex];
}
for (int i = 0; i < numVertex; i++) { //mark all matrix cells as false
for (int j = 0; j < numVertex; j++) {
matrix[i][j] = 0;
}
}
}
The line I'm confused about is:
matrix = (int**) new int*[numVertex]; //make matrix
What does the (int**) aspect do? Why would I choose to use this instead of matrix = new int**[numVertex];?
Thanks so much!
(int**)value is a C-style cast operation.
Notes:
Don't use those in C++, it tends to cause or hide problems, like mismatches between right and left side of an assignment.
The code is relatively low quality, proper C++ would rather use std::vector.
The code is also not complete, so little can be said with certainty about how it functions.
Note that matrix = new int**[numVertex]; as mentioned by you would create (for this example) a 3D array, because you'd have numVertex entries of int**.
The (int**) cast does not accomplish much, if anything at all, because if matrix is of type int**, there is no need for the cast (you get back an int** already from the new).
If column dimension is fixed, you can use vector of array there.
godbolt
wandbox
#include <vector>
#include <array>
#include <iostream>
#include <iomanip>
template<typename T, int col>
using row_templ = std::array<T,col>;
template<typename T, int col, template <typename,int> typename U = row_templ>
using mat_templ = std::vector<U<T,col>>;
int main()
{
constexpr int numVertex = 30;
constexpr int numEdge = 30;
constexpr int numCol = numVertex;
int numRow = numEdge;
using row_t = row_templ<int, numCol>; // alias to the explicit class template specialization
using mat_t = mat_templ<int, numCol>;
auto make_mat = [&](){ return mat_t(numRow); }; // define a maker if lazy
mat_t my_mat(numRow);
mat_t my_mat2 = make_mat(); // or just use our maker
// Due to that default allocator uses value initialization, a.k.a T().
// At this point, all positions are value init to int(), which is zero,
// from value init of array<int, col>() by the default allocator.
// numVertex x numEdge is one solid contaguous chunk and now ready to roll.
// range for
for (row_t r : my_mat) {
for (int n : r) {
std::cout << std::setw(4) << n;
}
std::cout << '\n';
}
// classic for
for (int i = 0; i < numRow; ++i) {
for (int j = 0; j < numCol; ++j) {
std::cout << std::setw(4) << (my_mat2[i][j] = i*numRow + numCol);
}
std::cout << '\n';
}
}
I am trying to insert int array x to int *v. here is my code . please provide me with optimal solutions and the reason behind it.
there is an error in this line. Instead of copying array value its taking garbage value. line v1=x;
class vector
{
int *v;
int size;
public:
vector(int m)
{
v = new int[size = m];
for (int i = 0; i < size; i++)
v[i] = 0;
}
vector(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
}
int operator *(vector &y)
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += v[i] * y.v[i];
return sum;
}
void disp()
{
for (int i = 0; i < size; i++)
cout << v[i] << " ";
cout << "\n";
}
};
int main()
{
clrscr();
int x[3] = { 1,2,3 };
int y[3] = { 4,5,6 };
vector v1(3);
//v1.disp();
vector v2(3);
v2.disp();
v1 = x;
v1.disp();
//v2=y;
v2.disp();
int r = v1 * v2;
cout << "R = " << r;
getch();
return 0;
}
You forgot to add the assignment operator in your vector class:
vector & operator=(int *a)
{
for (int i = 0; i < size; i++)
v[i] = a[i];
return *this;
}
In the the line
v1=x;
May be, you are expecting it to invoke the second constructor which takes int* as argument. But it won't happen.
It can be seen as Type Conversion from Basic type to Class type. where we expect appropriate constructor will get invoked.
see http://www.hexainclude.com/basic-to-class-type-conversion/
But remember, Constructor will be invoked only once after the creation of object.
Here, in the line
vector v1(3);
the first constructor was already invoked. Then the line
v1=x;
won't invoke the second constructor now.
For every class, = operator is default overloaded . That is the reason why we can easily assign objects to one another.
Therefore, the line v1=x invokes default overloaded assignment = operator.
Here, it treats address of array x i.e., &x[0] as address of class object. As it is not address of vector class object
=> it results a Segmentation fault.
YOUR ANSWER
To assign int array to int pointer i.e., to the member variable int* v of the vector class,
overload assignment operator = inside the class .
or
Initialize the class object to array in first line itself. i.e.,
vector v1=x; // modify the class constructor to have size as a constant.
I am writing a simple header file that can make a dynamic 2d array and put 0 in the row and col, print the array, and delete the array.
In Debug when stepping through, the 2d array gets initialized, it puts 0 in there, however when my_array.Print_Array(); called, the compiler skips it.
when i try to print the array from the main file it fails. any help would be appreciate it.
HEADER FILE:
class twoD_Array
{
public:
int **Array;
int *col, *row;
int size_col, size_row;
twoD_Array(int, int);
~twoD_Array();
void Print_Array();
};
twoD_Array::twoD_Array(int size_c, int size_r)
{
size_col = size_c;
size_row = size_r;
Array = new int *[size_col];
for (int i = 0; i < size_col; i++)
{
Array[i] = new int[size_row];
for (int j = 0; j < size_row; j++)
Array[i][j] = 0;
}
}
void twoD_Array::Print_Array()
{
for (int y_i = 0; y_i<size_col; y_i++)
{
for (int x_i = 0; x_i<size_col; x_i++)
std::cout << Array[y_i][x_i];
std::cout << std::endl;
}
}
twoD_Array::~twoD_Array()
{
for (int i = 0; i < size_row; i++)
delete[] Array[i];
delete[] Array;
}
Main File:
#include "stdafx.h"
#include <iostream>
#include "2D_Array.h"
int main()
{
int x, y;
std::cout << "how many x variables?" << std::endl;
std::cin >> x;
std::cout << "how many y variables?" << std::endl;
std::cin >> y;
twoD_Array my_array(x, y);
my_array.Print_Array();
return 0;
}
You are using the local variables in the constructor, but you're using the member variables in the Print_Array method, which are not initialized. You need to initialize the member variables size_col and size_row in the constructor where they are provided. Also, another thing to point out, in Print_Array method, you are using size_col instead of size_row for the x_i loop, which looks like a logical error.
I've rewritten the constructor and Print_Array to look this way:
twoD_Array::twoD_Array(int size_col, int size_row)
{
this->size_col = size_col;
this->size_row = size_row;
Array = new int *[size_col];
for (int i = 0; i < size_col; i++)
{
Array[i] = new int[size_row];
for (int j = 0; j < size_row; j++)
{
Array[i][j] = 0;
}
}
}
void twoD_Array::Print_Array()
{
for (int y_i = 0; y_i < size_col; y_i++)
{
for (int x_i = 0; x_i < size_row; x_i++)
{
std::cout << Array[y_i][x_i];
}
std::cout << std::endl;
}
}
In
twoD_Array::twoD_Array(int size_col, int size_row)
int size_col defines a new temporary and local to the constructor variable named size_col. This size_col has nothing to do with the member variable size_col and because they have the same name the local variable hides the member variable.
End result is in Print_Array the member variable size_col has not been set to anything, so Crom only knows what will happen.
Solution:
Set the member variable:
twoD_Array::twoD_Array(int col, int row): size_col(col), size_row(row)
The colon (:) tells the compiler that a Member Initializer List is coming. The Member Initializer List allows you to initialize class member before entering the body of the constructor. This is very important when you have a member variable that has no default constructor or requires expensive initialization you don't want to be forced to do twice. It' also allows you to initialize a base class.
Note that I also changed the names of the parameters to prevent future confusion.
And while we are here, let's head off what is likely to be OP's next problem by asking What is The Rule of Three? Seriously. Click the link. Save you a ton of debugging.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I'm relatively new at c++ and other object oriented languages as a whole (have done one semester of C classes and now I'm having c++ classes). I'm having problems concerning the making of a dynamically allocated two-dimensional array through a class with a classmate.
The exercise itself would be:
Prepare a class named "matrix" capable of storing two-dimensional
arrays dynamically allocated (for float variables). Remember that
information such as height and width have to be properly stored
somewhere, element pointers too.
The class needs to contain constructors that allow the creation of
objects using one of the following strategies: The creation of an
array consisting of MxN elements, example:
Array A (4, 5);
The creation of an empty array:
Array B;
The creation of an array that is a copy of another previous one:
Array C (A);
After some time trying to figure out why it wasn't working properly, our code is currently this:
obs: "Matriz" is how we call a two-dimensional array in our language.
Matriz.h
#pragma once
class Matriz{
public:
int l, c;
float** matriz;
void setL(int _l);
void setC(int _c);
int getL();
int getC();
Matriz();
Matriz(int _l, int _c);
Matriz(Matriz& m);
float **getMatriz();
float getElement(int pL, int pC);
void setElement(int pL, int pC, float value);
};
Matriz.cpp
#include "Matriz.h"
Matriz::Matriz(){
l = c = 0;
matriz = new float*[l];
for (int i = 0; i<l; i++) {
matriz[l] = new float[c];
}
}
Matriz::Matriz(Matriz& m){
l = m.getL();
c = m.getC();
matriz = new float*[l];
for (int i = 0; i<l; i++) {
matriz[l] = new float[c];
}
for (int i = 0; i<l; i++) {
for (int j = 0; j<l; j++) {
matriz[i][j] = m.matriz[i][j];
}
}
}
Matriz::Matriz(int _l, int _c){
l = _l;
c = _c;
matriz = new float*[l];
for (int i = 0; i<l; i++) {
matriz[l] = new float[c];
}
}
float **Matriz::getMatriz(){
return matriz;
}
int Matriz::getC(){
return c;
}
int Matriz::getL(){
return l;
}
void Matriz::setC(int _c){
c = _c;
}
void Matriz::setL(int _l){
l = _l;
}
float Matriz::getElement(int pL, int pC){
return matriz[pL][pC];
}
void Matriz::setElement(int pL, int pC, float value){
matriz[pL][pC] = value;
}
main.cpp
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
int l = 2, c = 2;
float **m;
m = new float*[l];
for (int i=0; i<2; i++) {
m[i] = new float[c];
}
Matriz a(2, 2);
a.setC(2);
a.setL(2);
cout << " c = " << a.getC() << " l= " << a.getL() << "\n";
for (int i = 0; i<l; i++) {
for (int j = 0; j<c; j++) {
a.setElement(i, j, 0);
cout << " Elemento " << 1 << " " << 1 << " = " << a.getElement(l, c) << "\n";
}
}
a.setElement(0, 0, 1); // <- this is just for testing
system("pause");
}
iostream and the class header are both included at stdafx.h
Compiling it at MSVS 2013 breaks at
void Matriz::setElement(int pL, int pC, float value){
matriz[pL][pC] = value;
}
And we're not really sure why, the debugger is giving me
"Unhandled exception at 0x01092E27 in ConsoleApplication15.exe: 0xC0000005: Access violation writing location 0xCDCDCDD1."
We suspect however that something with the array is wrong, and when the program tries to write something into an element of it, it simply doesn't exist/can't be reached, making it impossible to change the value of that specific element.
We're thankful for any help or advice, fell free to suggest improvements or coding advices, learning new things is always good =).
I think your error is actually here: a.getElement(l, c). l and c are the bounds for the array, e.g. 2, when your largest index should only ever be 1.
The other serious flaw (pointed out by twsaef) is your constructor:
for (int i = 0; i<l; i++) {
matriz[l] = new float[c];
}
Should be
for (int i = 0; i<l; i++) {
matriz[i] = new float[c];
}
While I'm at it, this is redundant:
Matriz a(2, 2);
a.setC(2);
a.setL(2);
Because the constructor for Matriz will set l and c for you.
Also, what are you planning on doing with this:
float **m;
m = new float*[l];
for (int i=0; i<2; i++) {
m[i] = new float[c];
}
Currently it's not used for anything.
Then, as PaulMcKenzie pointed out, what will happen to your dynamically allocated memory when a Matriz instance goes out of scope?
As Matt McNabb pointed out, what if you need to resize a Matriz instance when setC() or setL() are called? At the moment, they only set the member variable and do nothing with the memory.
in my C++ class at university, i have to implement a Directed, weighted graph. As internal representation i have to implement a two-dimensional array, which stores the information about the edges between the vertices in the graph.
okay, i´ve implemented a C++ class "TwoDimArray" with an overloaded [] operator.
it works well as long as i instantiate objects of TwoDimArray in main(). But it does not as class member.
My Class for representation of the graph is "DirectedGraph" and has a private member "adjacencyMatrix" of Type TwoDimArray*.
In the constructor of my DirectedGraph class i intend to fill the array with zeros initially, indicating "there is no edge between the nodes i and j".
okay, and this is where it all goes wrong. I can write till coordinate [0][2] (when initializing the graph with 3 nodes, so the array should have 3x3 cells). when trying to write at adress [1][0] the assignment operation crashes with segmentation fault. So the assignment operations succeed n times and fail beginning at n+1 (where n is the number of vertices).
Any ideas what i am doing wrong?
My TwoDimArray Class (first header, then implementation):
#ifndef TWODIMARRAY_H_INCLUDED
#define TWODIMARRAY_H_INCLUDED
class TwoDimArray{
private:
int* pArr;
int rows;
int cols;
public:
TwoDimArray(int rows, int cols);
int* operator[](int row);
~TwoDimArray();
};
#endif // TWODIMARRAY_H_INCLUDED
The implementation:
#include <TwoDimArray.h>
TwoDimArray::TwoDimArray(int nrOfRows, int nrOfCols){
rows = nrOfRows;
cols = nrOfCols;
//allocate memory
pArr = new int[rows * cols];
}
int* TwoDimArray::operator [](int row){
return &pArr[row * cols];
}
TwoDimArray::~TwoDimArray(){
delete[] pArr;
}
Directed Graph header:
#define DIRECTEDGRAPH_H_INCLUDED
#include <string>
#include <list>
#include <Vertex.h>
#include <TwoDimArray.h>
using namespace std;
/**
* DOCUMENTATION
* ======================
* object oriented Implementation
* of the abstract
* Datatype Directed Graph
* as C++ class
*/
class DirectedGraph{
private:
int maxVertices;
list<Vertex> vertices;
TwoDimArray* adjacencyMatrix;
bool edgeExists(string srcName, string tgtName);
int vertexExists(string vName);
public:
//DirectedGraph();
DirectedGraph(int maxVertices);
~DirectedGraph();
void AddVertex(Vertex& v);
void AddEdge(Vertex& source, Vertex& target, int weight);
int getMaxVertices() const;
list<Vertex> getVertexNames()const;
void PrintGraph();
};
#endif // DIRECTEDGRAPH_H_INCLUDED
Directed Graph Implementation (only the constructor):
DirectedGraph::DirectedGraph(int maxV){
this->maxVertices = maxV;
//initialize the array
this->adjacencyMatrix = new TwoDimArray(maxV, maxV);
int i = 0;
int j = 0;
for(i = 0; i <= maxVertices - 1; i++){
for(j = 0; j <= maxVertices - 1; j++){
// ==> the fatal assignment
//fails at i = 1 and j = 0
*adjacencyMatrix[i][j]=0;
cout << "assigned " << i << " " << j << "with 0"<<endl;
}
}
}
any suggestions?
i guess its not okay to declare the class member as TwoDimArray* instead of TwoDimArray, but otherwise it does not compile.
What i´ve also tried is:
DirectedGraph::DirectedGraph(int maxV){
this->maxVertices = maxV;
//try to instantiate TwoDimArray
TwoDimArray myArr(maxV, maxV);
this->adjacencyMatrix = myArr;
int i = 0;
int j = 0;
for(i = 0; i <= maxVertices - 1; i++){
for(j = 0; j <= maxVertices - 1; j++){
// ==> the fatal assignment
//fails at i = 1 and j = 0
myArr[i][j]=0;
cout << "assigned " << i << " " << j << "with 0"<<endl;
}
}
}
but it fails at the same point.
i am not very familiar with pointer logic in c++ i must admit...
any suggestions?
thanks in advance
Roland
You have violated the Rule of Three. The easiest way to solve that is to avoid directly allocating memory:
class TwoDimArray{
private:
std::vector<int> arr;
int rows;
int cols;
public:
TwoDimArray(int rows, int cols) : arr(rows * cols);
int* operator[](int row) { return &arr[cols*row]; }
};
One problem is that you're not providing a copy constructor and assignment operator for TwoDimArray.
This breaks the following:
TwoDimArray myArr(maxV, maxV);
this->adjacencyMatrix = myArr;
and possibly other code.
See What is The Rule of Three?