c0000005 exception (Access violation) while using JNI in C++ - c++

I started using JNI to call Java classes from C++ some weeks ago and today I encountered a peculiar situation. I am new to C++ (familiar with Java though), so this could be a n00b error. I have this class in Java called IntArray.java and I created another class in C++ called IntArrayProxy (split in a .h and a .cpp file) in order to access its methods through JNI. I also have another source file called IntArrayProxyTest.cpp which tests the IntArrayProxy methods.
In IntArrayProxy, I use a data member jobject* intArrayObject which contains the instance of the Java class and I pass this to every method of the IntArrayProxy class. My problem is that when I use it as a pointer (jobject*), after inserting (using insert) some integers and changing some of them (using setElement), when I use the same size() method twice, the executable I create crashes giving me a c0000005 exception (Access violation).
The first thing I noticed was that there is no problem at all if I use a normal jobject (not a jobject*) and the second one was that the exception occurs when I try to call a second non-void method. insert() and setElement(int, int) are both void, so I can call them as many times as I want. I tried it with almost all the non-void methods and the same exception was thrown each time I tried to call two non-void methods.
I thought that maybe the pointer somehow changed, so I tried printing the jobject* in each method but it stayed the same. The second explanation I found in forums was that maybe the object was destroyed but I don't know how to check it and why this could happen. I spent all day searching and debugging but no luck.
I think it's irrelevant but I am using the latest (32-bit) minGW compiler on Win7(64-bit). I also use the 32-bit jvm.dll. I am using the command line to compile it (g++ -I"C:\Program Files (x86)\Java\jdk1.6.0_26\include" -I"C:\Program Files (x86)\Java\jdk1.6.0_26\include\win32" IntArrayProxy.cpp IntArrayProxyTest.cpp -L"C:\Users\jEOPARd\Desktop\Creta\JNI samples" -ljvm -o IntArrayProxyTest.exe)
Hope someone can help me!!
Thanx in advance!!
Kostis
IntArray.java
package SortIntArray;
public class IntArray {
private int[] arrayOfInt;
private int cursor;
private static final int CAPACITY = 5;
public IntArray() {
arrayOfInt = new int[CAPACITY];
cursor = 0;
}
public void insert(int n) {
if (isFull()) {
System.out.println("Inserting in a full array!");
} else {
arrayOfInt[cursor++] = n;
}
}
public int removeLast() {
if (isEmpty()) {
System.out.println("Removing from an empty array!");
return -666;
} else {
return arrayOfInt[--cursor];
}
}
private boolean isEmpty() {
return cursor <= 0;
}
private boolean isFull() {
return cursor >= CAPACITY;
}
public String toString() {
if (isEmpty()) {
return "Empty Array";
}
String s = Integer.toString(arrayOfInt[0]);
for (int i = 1; i < cursor; i++) {
s += ", " + Integer.toString(arrayOfInt[i]);
}
return s;
}
public int size() {
return cursor;
}
public int getElement(int pos) {
return arrayOfInt[pos];
}
public void setElement(int pos, int newElement) {
arrayOfInt[pos] = newElement;
}
}
IntArrayProxy.h
#ifndef INTARRAYPROXY_H
#define INTARRAYPROXY_H
#include <jni.h>
using namespace std;
class IntArrayProxy {
JNIEnv *env;
jclass intArrayClass;
jobject *intArrayObject; //giati oxi pointer?
public:
IntArrayProxy(JNIEnv*);
void insert(int n);
int removeLast();
string toString();
int size();
int getElement(int);
void setElement(int pos, int newElement);
jobject *getIntArrayObject();
};
#endif /* INTARRAYPROXY_H */
IntArrayProxy.cpp
#include <stdio.h>
#include <cstdlib>
#include <iostream>
using namespace std;
#include "IntArrayProxy.h"
IntArrayProxy::IntArrayProxy(JNIEnv *envir) {
env = envir;
intArrayClass = env -> FindClass("SortIntArray/IntArray");
if (intArrayClass == NULL) {
cout << "--intArrayClass = NULL\n";
exit(0);
}
jmethodID IntArrayConstructor = env->GetMethodID(intArrayClass, "<init>", "()V");
if (IntArrayConstructor == NULL) {
cout << "--IntArrayConstructor = NULL";
exit(0);
}
cout << "IntArrayProxy: Got constructor\n";
jobject obj = env -> NewObject(intArrayClass, IntArrayConstructor);
intArrayObject = &obj; // I also can't assign intArrayObject directly at the above line, I don't know why (would be glad if you could tell me)
if (*intArrayObject == NULL) {
cout << "--*intArrayObject = NULL";
exit(0);
}
cout << "IntArrayProxy: Object created\n";
}
void IntArrayProxy::insert(int n) {
jmethodID insertID = env -> GetMethodID(intArrayClass, "insert", "(I)V");
if (insertID == NULL) {
cout << "--insertID = NULL";
exit(0);
}
env -> CallVoidMethod(*intArrayObject, insertID, (jint) n);
}
int IntArrayProxy::removeLast() {
jmethodID removeLastID = env -> GetMethodID(intArrayClass, "removeLast", "()I");
if (removeLastID == NULL) {
cout << "--removeLastID = NULL";
exit(0);
}
return (int) (env -> CallIntMethod(*intArrayObject, removeLastID));
}
string IntArrayProxy::toString() {
jmethodID toStringID = env -> GetMethodID(intArrayClass, "toString", "()Ljava/lang/String;");
if (toStringID == NULL) {
cout << "--toStringID = NULL";
exit(0);
}
jstring intArrayString = (jstring) env -> CallObjectMethod(*intArrayObject, toStringID);
string s = env -> GetStringUTFChars(intArrayString, NULL);
return s;
}
int IntArrayProxy::size(){
jmethodID sizeID = env -> GetMethodID(intArrayClass, "size", "()I");
if (sizeID == NULL) {
cout << "--sizeID = NULL";
exit(0);
}
return (int) (env -> CallIntMethod(*intArrayObject, sizeID));
}
int IntArrayProxy::getElement(int pos) {
jmethodID getElementID = env -> GetMethodID(intArrayClass, "getElement", "(I)I");
if (getElementID == NULL) {
cout << "--getElementID = NULL";
exit(0);
}
return (int) env -> CallObjectMethod(*intArrayObject, getElementID, (jint) pos);
}
void IntArrayProxy::setElement(int pos, int newElement){
jmethodID setElementID = env -> GetMethodID(intArrayClass, "setElement", "(II)V");
if (setElementID == NULL) {
cout << "--setElementID = NULL";
exit(0);
}
env -> CallVoidMethod(*intArrayObject, setElementID, (jint) pos, (jint) newElement);
}
jobject *IntArrayProxy::getIntArrayObject(){
return intArrayObject;
}
IntArrayProxyTest.cpp
#include <stdio.h>
#include <jni.h>
#include <cstdlib>
#include <iostream>
using namespace std;
#include "IntArrayProxy.h"
int main() {
cout << "--Starting..\n";
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=C:\\Users\\jEOPARd\\Desktop\\Creta\\JNI samples\\JNI tests\\build\\classes";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
cout << "--Creating VM..\n";
JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);
cout << "--VM created successfully!!\n";
delete options;
cout << "--Finding IntArray class..\n";
IntArrayProxy *intArrayProxy = new IntArrayProxy(env);
if (env->ExceptionOccurred())
env->ExceptionDescribe();
intArrayProxy -> insert(1);
intArrayProxy -> insert(10);
intArrayProxy -> insert(3);
intArrayProxy -> insert(88);
intArrayProxy -> insert(32);
intArrayProxy ->setElement(2, 5);
intArrayProxy ->setElement(3, 7);
cout << "Size: " << intArrayProxy -> size() << endl;
cout << "Size: " << intArrayProxy -> size() << endl;
cout << "--Destroying VM..\n";
jvm->DestroyJavaVM();
cout << "--Done!!!\n";
return 0;
}

In the proxy constructor:
intArrayObject = &obj;
You're taking the address of a variable on the stack. When the constructor exits, the address is no longer valid, hence the crash.
The intArrayObject (in the header) should be a jobject, not a jobject*, and the various uses of it should be changed accordingly.

Related

.exe file has triggered a breakpoint

I am writing a list-based multi-stack program. At first everything worked fine. Then I added a few exceptions. After that, the program began to build normally, but after throwing an exception, the program breaks. I opened the debugger and reached the place of error. There I found a place where another exception is thrown. But all that was written there is "MultiListStack.exe has triggered a breakpoint.". Please tell me, because of what it can be and how to fix it? Below I attach the code:
tmultiroot.h
//tmultiroot.h
//base abstract class for inheritance
#ifndef __MULTROOT_H__
#define __MULTROOT_H__
const int MemLimit = 4; // memory size
const int StackNum = 2; // number of stacks
typedef int TElem; // type of element
class TMultiRoot:
{
protected:
TElem Mem[MemLimit]; // memory for stacks (int array of MemLimit elements)
int DefaultStack; // current stack number
public:
TMultiRoot() { DefaultStack = 0; }
virtual bool IsEmpty(int ns) const = 0; // void control
virtual bool IsFull (int ns) const = 0; // overflow control
virtual void Put (int ns, const TData &Val) = 0; // put on the stack
virtual TData Get (int ns) = 0; // take from stack with deletion
// methods for working with the current stack
void SetDefaultStack(int ns) { DefaultStack = ns; } //current stack
int IsEmpty(void) const { return IsEmpty(DefaultStack); } // empty?
int IsFull(void) const { return IsFull (DefaultStack); } // full of?
void Put(const TData &Val) { Put(DefaultStack, Val); } // in the stack
TData Get(void) { return Get(DefaultStack); } // from the stack
};
#endif
multiliststack.h
//multiliststack.h
#ifndef __MULTILISTSTACK_H__
#define __MULTILISTSTACK_H__
#include "tmultiroot.h"
typedef int TElem; // type of element
class TMultiListStack: public TMultiRoot
{
protected:
int NextLink[MemLimit]; // next link index
int StackInd[StackNum]; // stack top index
int FirstFreeLink; // first free link index
public:
TMultiListStack();
virtual bool IsEmpty(int ns) const; // void control
virtual bool IsFull (int ns) const; // overflow control
virtual void Put (int ns, const TData &Val); // put on the stack
virtual TData Get (int ns); // take from stack with deletion
// utility methods
void Print(); // print stack values
int IsValid() { return 0; } // structure testing
};
#endif
exceptions.h
//exceptions.h
#ifndef _exceptions_h
#define _exceptions_h
//Exception class
class Exception{
protected:
int Line;
char* File;
char* Func;
char* Desc;
public:
Exception() {};//default constructor
Exception(int _Line, char* _File, char* _Func, char* _Desc); //constructor
Exception(const Exception& e); //copy constructor
~Exception(); //destructor
virtual void debug_print(); //display error message
virtual char* GetDesc(); //return error message
};
//stack exception class
class StackExc: public Exception {
protected:
int exc;//exception code, 0 - nomem, 1 - empty, 2 - full
public:
StackExc() {};//default constructor
StackExc(int _Line, char* _File, char* _Func, char* _Desc, int exc); //constructor
StackExc::~StackExc(); //destructor
int GetExc(); //get exception code
virtual void debug_print(); //display error message
};
#endif
ecxeptions.cpp
//exceptions.cpp
#include <cstring>
#include <iostream>
#include "exceptions.h"
//Exception class
Exception::Exception(int _Line, char* _File, char* _Func, char* _Desc) {
Line = _Line;
int size = strlen(_File) + 1;
File = new char[size];
strcpy(File, _File);
Func = new char[size];
strcpy(Func, _Func);
Desc = new char[size];
strcpy(Desc, _Desc);
}
//copy constructor
Exception::Exception(const Exception& e) {
Line = e.Line;
int size = strlen(e.File) + 1;
File = new char[size];
strcpy(File, e.File);
Func = new char[size];
strcpy(Func, e.Func);
Desc = new char[size];
strcpy(Desc, e.Desc);
}
//destructor
Exception::~Exception() {
delete[] File;
delete[] Func;
delete[] Desc;
}
//display exception
void Exception::debug_print() {
std::cerr << Line << " " << File << " " << Func << " " << Desc << std::endl;
}
char * Exception::GetDesc()
{
return Desc;
}
//stack exception class
StackExc::StackExc(int _Line, char* _File, char* _Func, char* _Desc, int exc)
: Exception(_Line, _File, _Func, _Desc), exc(exc) {
}
//destructor
StackExc::~StackExc() {
delete[] File;
delete[] Func;
delete[] Desc;
}
int StackExc::GetExc() {
return exc;
}
//display exception
void StackExc::debug_print() {
std::cerr << Desc << std::endl;
}
multiliststack.cpp
//multiliststack.cpp
#include <stdio.h>
#include "tmultiliststack.h"
#include "exceptions.cpp"
TMultiListStack::TMultiListStack()
{
for (int i = 0; i < MemLimit; i++)
NextLink[i] = i + 1;
NextLink[MemLimit - 1] = -1;
FirstFreeLink = 0;
for (int i = 0; i < StackNum; i++)
StackInd[i] = -1;
}
bool TMultiListStack::IsEmpty(int ns) const // void control
{
return StackInd[ns] < 0;
}
bool TMultiListStack::IsFull(int ns) const // overflow control
{
return FirstFreeLink < 0;
}
void TMultiListStack::Put(int ns, const TData &Val) // put on the stack
{
if (IsFull(ns)) {
throw StackExc(__LINE__, __FILE__, __FUNCTION__, "DataFull", 2); //after throwing this exception
} //it is being processed in main
else // And then an exception "MultiListStack.exe has triggered a breakpoint." occurs on this line
{
int k = FirstFreeLink;
FirstFreeLink = NextLink[k];
Mem[k] = Val;
NextLink[k] = StackInd[ns];
StackInd[ns] = k;
}
}
TData TMultiListStack::Get(int ns) // take from stack with deletion
{
TData temp = -1;
if (IsEmpty(ns))
throw StackExc(__LINE__, __FILE__, __FUNCTION__, "DataEmpty", 1);
else
{
int k = StackInd[ns];
temp = Mem[k];
StackInd[ns] = NextLink[k];
NextLink[k] = FirstFreeLink;
FirstFreeLink = k;
}
return temp;
}
void TMultiListStack::Print() // print stack values
{
int pind, ind, k;
for (int ns = 0; ns < StackNum; ns++)
{
printf("ns=%d -> ", ns);
pind = -1;
ind = StackInd[ns];
while (ind > -1) // pointer wrapping
{
k = NextLink[ind];
NextLink[ind] = pind;
pind = ind;
ind = k;
}
ind = pind;
pind = -1;
while (ind > -1) // pointer recovery and printing
{
printf("%d ", Mem[ind]);
k = NextLink[ind];
NextLink[ind] = pind;
pind = ind;
ind = k;
}
printf("\n");
}
}
main.cpp
#include <windows.h>
#include <conio.h>
#include <iostream>
#include "tmultiliststack.h"
using namespace std;
void main()
{
TMultiListStack mst;
int ms = 2, ns, code, temp, val = 0;
setlocale(LC_ALL, "Russian");
srand(1);
cout << "System Testing N Stacks" << endl;
while (1)
{
try {
val++;
code = random(4); // operation
ns = random(ms); // stack number
Sleep(1000);
if (code < 3) {
cout << "Put " << val << " in " << ns << endl;
mst.Put(ns, val);
mst.Print();
}
else {
cout << "Get from " << ns << endl;
temp = mst.Get(ns);
mst.Print();
}
}
catch (StackExc exc) {
exc.debug_print();
}
if (_kbhit())
break;
}
cout << "Stack Printing" << endl;
mst.Print();
}
When the program starts, 4 values ​​are put on the zero stack. But at the fifth iteration, when the fifth value is to be added to the zero stack, overflow occurs. Because of this, my exception is thrown. Then it is processed in main. And after that, this incomprehensible exception is thrown. No details about it are displayed, so I don’t understand what to do. Tell me, please, how to fix it?

auto, template? How to construct method returning different datatypes

[INFO]
I'm new here and... new to programming. I'm learning C (with very little of C++) for about a year and now I'm stuck. I'm currently writing my first bigger application for training purposes and as every programist - I'm trying to be as lazy as I could. My application is based on Simple Fast Multimedia Library (SFML) for drawing graphics and of course C/C++ for logic. I was tired of having lots of different variables hidden in code (like Window Resolution, Window Position etc.) soo I started writing class for reading *txt files with configuration (You know: config.ini with something like "iWindowResolutionX=1920;"). Algorythm that opens *txt files, interprets them and pulls out needed data is working (proppably it is very bad - but hey, it is working :P)
[QUESTION]
I'm stuck with very basic thing.
I have object of my config file reader class and I want to achieve something like this:
Int main()
{
int WindowResolutionX = 0; //nothing special - int with value of 0.
CfgReader cfg_object("config.ini"); // object of CfgReader class with custom
constructor passing name of *txt
configuration file.
WindowResolutionX = cfg_object.Search("iWindowResolutionX"); // As you see - I want to write a code that calls method "Search" on cfg_object. This method takes variable name as parameter and after sucsess (value found) returns it.
And here I am stuck. How to force method to return different basic data types( char, int, float etc. )?
}
I've tried defining method return type as "auto", but it gives me an error "a function that returns 'auto' cannot be used before it is defined" (I don't understand what's VS is talking to me here) and then errors about trying to return different datatypes than firstly selected (this is simple, if compiler see "return value" for the first time, it can't allow me to return any other datatype).
Next thing I've tried was template methods, but I'm to stupid to understand it ;)
Ok, there is simple solution - I can copy my Search method X times for X datatypes I want and just simply overload it - but this is not elegant solution and won't teach me anything new. Below my code:
"CfgReader.h"
#pragma once
#include "fstream"
#include <iostream>
#include <string>
class CfgReader
{
public:
FILE *fp;
const char * cfg_filename;
size_t filesize;
std::string line;
int int_val;
float float_val;
char char_val;
bool bool_val;
long long_val;
std::string string_val;
size_t size_t_val;
public:
void OpenFile(const char * filename);
void CloseFile();
auto Search(const char * search_val);
void Show_content();
int r_int();
char r_char();
float r_float();
size_t r_size_t();
long r_long();
bool r_bool();
std::string r_string();
CfgReader();
CfgReader(const char *);
~CfgReader();
};
"CfgReader.cpp"
#include "CfgReader.h"
#pragma warning(disable: 4996)
CfgReader::CfgReader()
{
CfgReader("");
}
CfgReader::CfgReader(const char * filename)
{
if ((sizeof(filename) == 1) && (filename[0] == 0))
{
std::cout << "\n CfgReader No filename.";
cfg_filename = "";
fp = NULL;
}
else
{
std::cout << "\n test";
line = "";
int_val = NULL;
float_val = NULL;
char_val = NULL;
bool_val = false;
long_val = NULL;
string_val = "";
size_t_val = NULL;
cfg_filename = filename;
OpenFile(cfg_filename);
}
}
void CfgReader::OpenFile(const char * filename)
{
fp = fopen(filename, "rb");
if (fp != NULL)
{
std::cout << "\n good!";
}
else
{
std::cout << "\n Error, could not open file.";
}
rewind(fp);
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
rewind(fp);
std::cout << "\n filesize: " << filesize;
//system("pause");
}
void CfgReader::Search(const char * search_val)
{
size_t search_val_length = 0;
for (search_val_length; search_val[search_val_length] != '\0';
search_val_length++);
std::string test;
if (fp == NULL)
{
std::cout << "\n Error, file not loaded!";
}
else
{
char first_letter = 0;
bool match = false;
size_t counter = 0;
rewind(fp);
while (match == false)
{
while (first_letter != 13)
{
fread(&first_letter, sizeof(char), 1, fp);
}
if (first_letter == 13)
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == 10)
{
do
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == search_val[counter])
{
test += first_letter;
counter++;
if(counter==search_val_length)
{
match = true;
break;
}
}
else
{
counter = 0;
test = "";
break;
}
} while (first_letter != 61);
if (test == search_val || match == true)
{
match = true;
break;
}
}
}
std::cout << "\n ftell(fp): " << ftell(fp);
if (ftell(fp) == filesize) break;
}
if (match == false)
{
std::cout << "\n ERROR, no such VALUE!";
}
else
{
std::cout << "\n test string = " << test;
//system("pause");
//Show_content();
///line = test;
///test = "";
while (first_letter != 13)
{
fread(&first_letter, sizeof(char), 1, fp);
if (first_letter == 61)continue;
test += first_letter;
}
std::cout << "\n test string VALUE (string):" << test << std::endl;
switch (line[0])
{
case 'i':
int_val = std::stoi(test);
std::cout << "\n int_val: " << int_val;
//return int_val;
//a = int_val;
break;
case 'f':
float_val = std::stof(test);
std::cout << "\n float_val: " << float_val;
//return float_val;
//a = float_val;
break;
case 'b':
if (test[0] == 'f' || test[0] == '0') bool_val = false;
else bool_val = true;
std::cout << "\n bool_val: " << bool_val;
//return bool_val;
//a = bool_val;
break;
case 'l':
long_val = std::stol(test);
std::cout << "\n long_val: " << long_val;
//return long_val;
//a = long_val;
break;
case 's':
string_val = test;
std::cout << "\n string_val: " << string_val;
//return string_val;
// a = string_val;
break;
case 't':
size_t_val = std::stoul(test);
std::cout << "\n size_t_val: " << size_t_val;
//return size_t_val;
//a = size_t_val;
break;
}
}
}
}
int CfgReader::r_int()
{
return int_val;
}
char CfgReader::r_char()
{
return char_val;
}
float CfgReader::r_float()
{
return float_val;
}
size_t CfgReader::r_size_t()
{
return size_t_val;
}
long CfgReader::r_long()
{
return long_val;
}
bool CfgReader::r_bool()
{
return bool_val;
}
std::string CfgReader::r_string()
{
return string_val;
}
void CfgReader::Show_content()
{
std::cout << "\n //--------------------------CfgReader.Show_content()------------------------\\"<<std::endl;
if (fp != NULL)
{
rewind(fp);
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
char literka;
rewind(fp);
while (ftell(fp) != filesize)
{
fread(&literka, sizeof(char), 1, fp);
std::cout << "\n" << (short)literka << " - " << literka;
}
}
else
{
std::cout << "\n Error: fp == NULL.";
}
std::cout << "\n \\--------------------------/CfgReader.Show_content()------------------------// \n";
}
void CfgReader::CloseFile()
{
fclose(fp);
}
CfgReader::~CfgReader()
{
}
"Source.cpp"
#pragma warning(disable:4996)
#include "CfgReader.h"
int main()
{
CfgReader Config("config.ini");
Config.Search("iBitDepth");
system("pause");
return 0;
}
"config.ini"
//------------------------ M_UPTIME config FILE ------------------------//
[Window]
iWindowResX=1920
iWindowResY=1080
fWindowScale=1
iWindowPosX=-1920
iWindowPosY=0
iBitDepth=32
[Screen Saver]
iScreenSaverTimeLimit=600
[TestValues]
bThisIsBool=false
bThisIsBoolToo=true
sThisIsString=Ala ma kota a kot ma ale
Anyone can point me out how to convert Search method for being able to either return different datatypes:
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
value_1 = Config.Search("iBitDepth");
return 0;
}
or work as here: (CfgReader object gets reference to variable as a parameter)
int main()
{
int value_1 = 0;
CfgReader Config("config.ini");
Config.Search("iBitDepth", &value_1);
return 0;
}
If someone could also give me a example on how to properly convert my Search method for template method.
Thanks for responces, I'm out of ideas...
I'd suggest to implement separate methods for each data type.
You know data type of the target variable, right? Then you can do few methods like this:
int GetInt(const char* name, int defaultValue = 0) const;
std::string GetString(const char* name, const char* defaultValue = "") const;
And call appropriate method:
int bitDepth = config.GetInt("Window.iBitDepth", 24);
One way to do this using templates is to use "lexical cast" (as Boost calls it). Implementing simple lexical cast function using std::istringstream is relatively simple:
template<typename TargetType>
TargetType lexical_cast(const std::string& source)
{
TargetType result;
// create a stream for reading, initially containing source string
std::istringstream stream(source);
// read one value of type TargetType...
stream >> result;
// ...and return it
return result;
}
This will work for all types for which operator >> is overloaded, which includes primitive types, such as float or int. Additionally, you can overload the operator for your custom types.
With this, you can implement Search template method which converts a string to requested type:
template<typename TargetType>
TargetType Search(const std::string& key) const
{
std::string valueAsStr = // get it somehow, from a map, or file...
return lexical_cast<TargetType>(valueAsStr);
}
I've tried defining method return type as "auto", but it gives me an error "a function that returns 'auto' cannot be used before it is defined" (I don't understand what's VS is talking to me here)
Personally, I don't use VS too often, but I suppose this means that compiler must see body (definition) of the method when you call it. This is necessary - after all, when using auto (without trailing return type), compiler has to deduce returned type based on body of the function.

C++ getenv() wrapper function not setting the value

The cplusplus.com documentation on getenv() states...
The pointer returned points to an internal memory block, whose content or validity may be altered by further calls to getenv
...which I take to mean, "If you want to keep the content, copy it." So, since I need to retrieve several variables, I wrote a couple of little wrapper functions:
#include <iostream>
#include <string.h>
using namespace std;
void getEnv (char *val, const char *var) {
val = nullptr;
char *enVar = getenv(var);
if (enVar != nullptr) {
val = new char[strlen(enVar) + 1];
strcpy(val, enVar);
}
}
void getEnv (int &val, const char *var) {
val = -1;
char *enVar = getenv(var);
if (enVar != nullptr) {
val = atoi(enVar);
}
}
int main() {
char *textMode = nullptr;
int cLen = 0;
getEnv(cLen, "CONTENT_LENGTH");
cout << cLen << endl << endl;
getEnv(textMode, "TEXT_MODE");
if (textMode == nullptr)
cout << "Not set.";
else
cout << "[" << textMode << "]<br>\n";
return 0;
}
The int version works as expected, but I get nothing back from the char version, and I mean nothing: if I don't initialize *textMode at declaration it remains an uninitialized pointer.
It's pointers, right? Right? I know it is. Gotta be pointers. I'll figure them out one of these days, but hey -- at least I got my linked list to work! Yay!
Your second function takes val (an int) by reference: void getEnv (int &val, const char *var) and so can modify the variable passed to it as you expect.
Your first function takes val (a char*) by value: void getEnv (char *val, const char *var) so modifying val has no affect on the variable passed to it. A simple solution is to simply take it as a reference as well: void getEnv (char *&val, const char *var)
Follow up to my comments and the OP's response to them.
Here's what I was thinking:
#include <iostream>
#include <string.h>
using namespace std;
// Use a class to encapsulate the data need to be captured
// in an environment variable.
class EnvironmentVariable
{
public:
EnvironmentVariable(char const* name) : name_(name), isSet_(false)
{
char *val = getenv(name);
if ( val != nullptr )
{
isSet_ = true;
this->value_ = val;
}
}
bool isSet() const
{
return isSet_;
}
void getValue(char const*& val) const
{
if ( isSet_ )
{
val = this->value_.c_str();
}
else
{
val = nullptr;
}
}
void getValue(int& val) const
{
if ( isSet_ )
{
val = stoi(this->value_);
}
else
{
val = 0; // Find a suitable default value
}
}
private:
std::string name_;
std::string value_;
bool isSet_;
};
int main() {
char const* textMode = nullptr;
int cLen = 0;
EnvironmentVariable env1("CONTENT_LENGTH");
env1.getValue(cLen);
cout << cLen << endl << endl;
EnvironmentVariable env2("TEXT_MODE");
env2.getValue(textMode);
if (textMode == nullptr)
cout << "Not set.\n";
else
cout << "[" << textMode << "]<br>\n";
return 0;
}

Proper set external pointer for allocate memory in C++

How to use properly external pointers for allocating memory in constructors and deallocating in destructors in C++? Following is a code example that is not working properly. Please consider it.
#include <iostream>
using namespace std;
class Foo
{
public:
Foo() : str(nullptr)
{
str = new string();
}
~Foo()
{
if (str != nullptr)
{
delete str;
str = nullptr;
}
}
void getString(string ** pStr)
{
*pStr = str;
}
private:
string * str;
};
int main()
{
string * mainStr = nullptr;
Foo().getString(&mainStr);
if (mainStr == nullptr)
cout << "is null";
else
cout << "is not null";
return 0;
}
How to write above code in order to mainStr variable has the correct value (nullptr in this case)?
In C++, you will need an instance of an object in order to use it's non-static member functions.
In your case:
int main(void)
{
Foo my_foo;
std::string * p_string = nullptr;
my_foo.getString(&p_string);
if (mainStr == nullptr)
cout << "is null";
else
cout << "is not null";
return 0;
}
You will need to test pStr in getString for null, as assigning to a null pointer is undefined behavior.

the same addresses of different nodes

I try to write a bidirectional list. I must use overloaded operators([] and +=). [] - access to given node. += - add node to my list. I wrote these methods and it looks ok, but it doesn't work and I have no idea why.
here are core lines of my code:
//********************************************************
CLista::CNode* CLista::operator[](int i_index)
{
int i_help = 0;
CNode* c_result = &c_root;
while(i_help < i_index)
{
c_result = c_result->getNext();
i_help++;
}
return c_result;
}
//*********************************************************
void CLista::operator+=(void* pv_object)
{
if(i_numNodes == 0)
{
c_root = CNode(pv_object);
}
else
{
CNode c_new = CNode(pv_object);
CNode* c_help = this->operator[](i_numNodes - 1);
c_new.setPrevious(c_help);
(*c_help).setNext(&c_new);
}
i_numNodes++;
}
int _tmain(int argc, _TCHAR* argv[])
{
CLista list = CLista();
string s1 = string("first");
void* wsk1 = &s1;
string s2 = string("second");
void* wsk2 = &s2;
string s3 = string("third");
void* wsk3 = &s3;
list += wsk1;
list += wsk2;
list += wsk3;
void* res1 = (*list[0]).getObject();
void* res2 = (*list[1]).getObject();
void* res3 = (*list[2]).getObject();
cout << "res1: " << res1 << endl;
cout << "res2: " << res2 << endl;
cout << "res3: " << res3 << endl;
cout << "wsk1:" << wsk1 << endl;
cout << "wsk2:" << wsk2 << endl;
cout << "wsk3:" << wsk3 << endl;
}
and here is header:
class CLista
{
public:
class CNode
{
public:
CNode(void)
{
pc_next = NULL;
pc_previous = NULL;
}
CNode(void* pv_object)
{
pc_next = NULL;
pc_previous = NULL;
this->pv_object = pv_object;
}
CNode* getNext(){return pc_next;};
CNode* getPrevious(){return pc_previous;};
void* getObject(){return pv_object;};
void setNext(CNode* pc_next);
void setPrevious(CNode* pc_previous);
private:
CNode* pc_next;
CNode* pc_previous;
void* pv_object; // czy to jest dobrze?
};
CNode c_root;
int i_numNodes;
public:
CLista(void);
~CLista(void);
CNode* operator[](int index);
void operator+=(void* object);
};
When I add third element to list and then check it, it is strange problem: addresses of res2 and res3 are the same.
In your operator += function, you create a local CNode called c_new that you link into your linked list. When the scope ends (which happens before the function returns), that local is destructed, leaving the list dangling (pointing at a no longer valid CNode, whose memory is about to be reused for some other local variable, such as the next c_new created on the next call to the function).
Using/accessing an object after it has gone out of scope and been destroyed is undefined behavior, so will generally crash or otherwise misbehave.