I am trying to work with pointers - you know experiment.
My code will work fine if I remove the pointer for name and the dereferences for
this->name. But I wouldn't really be learning anything.
// Example program
#include <iostream>
#include <string>
using namespace std;
string dogsbreed[3];
struct dog
{
string *name;
string breed;
int age;
void set_dogs_breed()
{
dogsbreed[0] = "Collie";
dogsbreed[1] = "Poodle";
dogsbreed[2] = "Pit Ball";
}
void set_dog_name(string names)
{
*this->name = names;
}
string get_dog_name()
{
return *this->name;
}
};
int main()
{
dog doggies;
doggies.set_dogs_breed();
doggies.set_dog_name("Socks");
doggies.get_dog_name();
}
In regards to
void set_dog_name(string names)
{
*this->name = names;
}
Everything works fine - makes sense, name is a pointer, I dereference name in set_dog_breed() and change it's value.
string get_dog_name()
{
return *this->name;
}
Causes
29:23: warning: 'doggies' may be used uninitialized in this function
[-Wmaybe-uninitialized]
35:9: note: 'doggies' was declared here
OK doggies is uninitialized but the compiler didn't mind when I wasn't using pointers - I am unclear as to why this is required or even if that is the actual issue.
The warning message is correct, the doggies object is uninitialized, you never initialize the member variables which has to be done in a constructor.
And since you don't initialize the object, the member variable name will have an indeterminate value and using the variable in any way except to initialize it will lead to undefined behavior.
The compiler doesn't stop you from doing bad things, it might detect them but it isn't required to do anything about it. And C++ doesn't have any kind of run-time checking either, the compiler and run-time system will happily let you shoot yourself in the foot.
Also, if you mostly use the dereference operator to access a pointer then you probably don't need a pointer in the first place.
The member string *name has no memory allocated for it. So you'd get a segmentation fault inside set_dog_name, where you assign another string to it.
Additionally, you don't initialize the members either in-class or in a constructor. This perhaps is pointed out by the compiler. GCC 5.2 however shows no warnings or errors, with both -Wall and -Wextra. I just get a segmentation fault when running the program. Live demo here.
Aside:
Initializing the global dogsbreed array is in no way the struct's concern. Instead you could make the variable as the struct's static member and initialize it separately.
struct dog {
static string dogsbreed[3];
};
string dog::dogsbreed[3] = { "Collie", "Poodle", "Pit Ball" } ;
Related
I have two projects, one basic client and a dynamic library.
Here's what happens in the client:
int main()
{
Scrutinizer scru;
scru.Scrutinize();
return 0;
}
In the DLL, The Scrutinizer class is as such (__declspec(dllexport) and such omitted for Clarity)
Header
class ProcessesGenerator;
class Scrutinizer
{
public:
Scrutinizer();
~Scrutinizer();
ProcessesGenerator *ProcGenerator
void Scrutinize();
};
The forward declaration of ProcessesGenerator was 'mandatory' for me to avoid some kind of circular reference.
Constructor in .cpp file
Here is how I initialize it:
Scrutinizer::Scrutinizer()
{
ProcGenerator = &ProcessesGenerator();
}
More about this ProcessesGenerator class:
Header
class ProcessesGenerator
{
public:
ProcessesGenerator();
~ProcessesGenerator();
WinFinder winFinder;
std::vector<std::string> fooCollec;
void GenerateProcesses();
};
ProcessesGenerator.cpp
Constructor:
ProcessesGenerator::ProcessesGenerator()
{
//winFinder = WinFinder();//problem will be the same with or without this line
fooCollec = std::vector<std::string>{"one", "two", "three"};
}
A breakpoint in the constructor shows that the vector is initialized with the chosen values.
Problematic function:
void ProcessesGenerator::GenerateProcesses() {
std::string foo = "bar";
fooCollec = std::vector<std::string>{};//read access violation
fooCollec.push_back(foo);//read access violation
winFinder.SomeVector= std::vector<std::string>{};//read access violation
}
Once there, I Can see that the size of vector is reset to 0. Any attempt to re-initialize it, or to push an element results in read access violation .Same with the vecotr member of its WinFinder member. I guess the flaw is obvious, but I really don't get it,
Thanks!
Your problem is with
Scrutinizer::Scrutinizer()
{
ProcGenerator = &ProcessesGenerator();
}
What you are doing is taking the address of a temporary object. That object will be destroyed and the end of that line and you will be left with a pointer that doesn't point to a valid object.
The old way to fix it would be to use
Scrutinizer::Scrutinizer()
{
ProcGenerator = new ProcessesGenerator();
}
But now you have to implement the copy constructor, copy assignment operator, and the destructor. Since you have a modern compiler what you can do instead is make ProcGenerator a std:unique_ptr<ProcessesGenerator> and then Scrutinizer() becomes
Scrutinizer::Scrutinizer() : ProcGenerator(make_unique<ProcessesGenerator>()) {}
I would also like to add that &ProcessesGenerator(); should not even compile. Unfortunately MSVS has a non-standard extension that allows this to compile. You can turn on the /Za compiler option (enforce ANSI compatibility) and then you should get an error like
error C2102: '&' requires l-value
The line ProcGenerator = &ProcessesGenerator(); makes a temporary ProcessesGenerator, takes its address and then puts it in your ProcGenerator pointer. The temporary is then destroyed, leaving garbage.
You probably wanted to be allocating it on the heap ProcGenerator = new ProcessesGenerator; but even in that case I would strongly suggest using unique_ptr instead of a raw pointer.
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
I wrote a small example which I think explains the problem very well.
#include <vector>
using namespace std;
class container{public:container(){}
vector<int> LongList;
bool otherInfo;
};
class Ship
{
public:Ship(){}
container* pContainer;
};
int main()
{
//Create contianer on ship1
Ship ship1;
ship1.pContainer = new container;
ship1.pContainer->LongList.push_back(33);
ship1.pContainer->otherInfo = true;
Ship ship2;
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = 0;
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
//and the program crashes
return 0;
}
The compiler cannot determine if you are introducing undefined behavior like shown in your example. So there's no way to determine if the pointer variable was initialized or not, other than initializing it with a "special value".
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
The best practice is always to initialize the pointer, and check before dereferencing it:
class Ship {
public:
Ship() : pContainer(nullptr) {}
// ^^^^^^^^^^^^^^^^^^^^^
container* pContainer;
};
// ...
if(ship1.pContainer->LongList) {
ship1.pContainer->LongList.push_back(33);
}
As for your comment:
So there are no compiler flags that could warn me?
There are more simple and obvious cases, where the compiler may leave you with a warning:
int i;
std::cout << i << std::endl;
Spits out
main.cpp: In functin 'int main()':
main.cpp:5:18: warning: 'i' is used uninitialized in this function [-Wuninitialized]
std::cout << i << std::endl;
^
See Live Demo
One good practice to enforce the checks is to use std::optional or boost::optional.
class Ship
{
public:
Ship() : pContainer(nullptr) {}
std::optional<container*> Container()
{
if(!pContainer)
return {};
return pContainer;
}
private:
container* pContainer;
};
It will force you (or better: provide a firm reminder) to check the result of your getter:
std::optional<container*> container = ship1.Container();
container->otherInfo; // will not compile
if(container)
(*container)->otherInfo; // will compile
You would always need to check the result of operation if you use pointers. What I mean is that with optional the situation is more explicit and there's less probability that you as the programmer will forget to check the result.
It seems that you are looking for a way to make your code
bool info = ship1.pContainer->otherInfo;
work even though the pContainer may be null.
You can use a sentinel object, which holds some default data:
container default_container;
default_container.otherInfo = false; // or whatever the default is
Then use a pointer to the sentinel object instead of a null pointer:
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = &default_container; // instead of 0
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
If you use this, you should make sure the sentinel object cannot be destroyed (e.g. make it a static member, or a singleton).
Also, in the constructor, initialize your pointers so they point to the sentinel object:
class Ship
{
public: Ship(): pContainer(&default_container) {}
...
};
I found an additional solution. It is admittedly not preventing the access of uninitialized objects, but at least the program crashes AND returns an error message, that enables us to correct our mistake. (This solution is particularly for the g++ compiler.)
First of all set the compiler flag _GLIBCXX_DEBUG. Then instead of naked pointer use unique_ptr.
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class container{
public:container(){}
int otherInfo = 33;
};
class Ship
{
public:Ship(){}
std::unique_ptr<container> upContainer;
};
int main()
{
Ship ship1;
cout<<ship1.upContainer->otherInfo<<endl;
return 0;
}
This code will produce an error:
std::unique_ptr<_Tp, _Dp>::pointer = container*]: Assertion 'get() != pointer()' failed.
Hence telling us that we should probably include an if(ship1.upContainer) check.
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
Good practice would be to initialize everything in the constructor.
Debatable better practice is to initialize everything in the constructor and provide no way of modifying any members.
Problem: Getting an error when running my .exe
An unhandled exception of type 'System.AccessViolationException'
occurred in AddingWrapper.dll
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
In the console it writes this:
Unhandled Exception: System.AccessViolationException : attempted to
read or write protected memory. This is often an indication that other
memory is corrupt. at gcroot (Add ^).. P$AAVAdd##(gcroot(Add^)) at
AddingWrapper.Adding(AddingWrapper, Int32* x, Int32* y)
Code snippet:
VB code:
Public Class Add
Public Function Adding(ByVal x As Double, ByVal y As Double) As Integer
Return x + y
End Function
End Class
AddingWrapper.h:
#pragma once
#include "stdafx.h"
class AddingWrapperPrivate;
class __declspec(dllexport) AddingWrapper {
private: AddingWrapperPrivate* _private;
public: AddingWrapper();
int Adding(int* x, int* y);
~AddingWrapper();
};
AddingWrapper.cpp
#include "stdafx.h"
#include "AddingWrapper.h"
#using "Class1.dll"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class AddingWrapperPrivate {
public: msclr::auto_gcroot<Add^> add;
};
AddingWrapper::AddingWrapper()
{
_private = new AddingWrapperPrivate();
_private->add = gcnew Add();
};
int AddingWrapper:: Adding(int* x, int* y) {
return _private->add->Adding(*x, *y);
};
AddingWrapper::~AddingWrapper()
{
delete _private;
};
calling code:
#include "stdafx.h"
#include "AddingWrapper.h"
#include <iostream>
int main()
{
int *a = 0;
int *b = 0;
AddingWrapper *add;
int results = add->Adding(a,b);
std::cout << "here is the result";
std::cout << results;
return 0;
}
Could it be due to my Class1.dll in AddingWrapper.cpp is using VB.net? Or it's a question of other issues? All the other threads seem to all differ in answer (i.e one is suggesting the user account doesn't have all the rights to the computer). If ever I missed on of those thread, please link it to me, this error is killing me
I should also add this error is at run time not compile time.
In the main function, you are using a "null" object pointer and passing in NULL pointers - that will cause the error you are seeing.
int main()
{
int a = 1;
// ^^^ remove the pointer (and give it a "interesting" value)
int b = 2;
// ^^^ remove the pointer
AddingWrapper add; // remove the pointer (or allocate with new)
// ^^^ remove the pointer
int results = add.Adding(&a, &b); // pass in the address of the integers
// ^^^ syntax change
std::cout << "here is the result";
std::cout << results;
return 0;
}
The variable a, b and add where only pointers, pointing to nothing; this causes access violations. Changing them to be automatic objects ("on the stack") will fix this. If dynamic objects are needed, you can new them (and delete them afterwards); but favour library utilities such as std::shared_ptr and std::unique_ptr etc. to help manage the lifetime of the object.
Several things:
You haven't shown your VB code. Since you've written an unmanaged class, not a managed one, it seems likely that either the import is not correct, or that you're passing a bad pointer.
Why are you passing an int* to the wrapper, only to dereference it right there? Why not pass an int?
You're in C++/CLI, why are you not writing a managed class? You wouldn't need auto_gcroot, and you don't need to deal with DLL imports/exports: VB.Net would be able to see your class the same as it can see any .Net class, and reference it just as easily as you can reference any .Net library.
Edit
OK, it wasn't obvious that you were trying to call some VB.Net code from C++. I thought you were trying to go the other direction.
The problem is almost certainly that you're passing a bad pointer to AddingWrapper::Adding.
You don't need to pass a pointer for basic data types, so you can get rid of that entire thing if you want. The fact that it's a double in VB but an int in C++ is fine, C++/CLI knows that the VB code takes a double and will convert appropriately.
Also, note that you're not passing a pointer between managed and unmanaged code. You're passing a pointer from one unmanaged class to another unmanaged class (whatever calls AddWrapper, to AddWrapper), but across the managed/unmanaged border, you're passing a plain old int.
I am having an issue with segmentation faults when trying to access a class member, which is a structure, from within a class function. I assume I am declaring this wrong somewhere, but I can't see what the problem is. I have tried many variations with no luck so far. Any help would be greatly appreciated.
program.h:
struct ButtonState {
int analog_pin;
};
class LEDGarden {
public:
ButtonState *the_state;
LEDGarden(void) {}
void init(void);
void initButtons(void);
};
program.cpp:
#include "program.h"
void LEDGarden::init(void) {
ButtonState *the_state = new ButtonState();
the_state->analog_pin = 5;
initButtons();
}
void LEDGarden::initButtons(void) {
// The problem happens here.
the_state->analog_pin = 5;
}
int main() {
LEDGarden garden;
garden.init();
}
The segmentation fault happens when I try to make an assignment in the structure in the function initButtons. I am at quite a loss as to what the problem is.
Note that this program works fine for me when using gcc so long as I don't use the -O2 flag. Using clang I get the segfault regardless of the compilation flags.
Your LEDGarden has a pointer to a ButtonState which you never set.
The init method shadows the member variable with a local of the same name (so the member variable is not set when you go to use it). try
void LEDGarden::init(void) {
this->the_state = new ButtonState();
the_state->analog_pin = 5;
initButtons();
}
What you should probably do is get rid of init() and make it a constructor.
The different behaviors probably depends on what the member variable is set to null or random memory location (which may be "good" or "bad", but never "right" ;-)
I have the following structure:
struct CountCarrier
{
int *CurrCount;
};
And this is what I want to do:
int main()
{
CountCarrier carrier = CountCarrier();
*(carrier.CurrCount) = 2; // initialize the *(carrier.CurrCount) to 2
IncreaseCount(&carrier); // should increase the *(carrier.CurrCount) to 3
}
void IncreaseCount(CountCarrier *countCarrier)
{
int *currCounts = countCarrier->CurrCount;
(*currCounts)++;
}
So, my intention is specified in the comments.
However, I couldn't get this to work. For starters, the program throws an exception at this line:
*(carrier.CurrCount) = 2;
And I suspect the following line won't work as well. Anything I did wrong?
struct CountCarrier
{
int *CurrCount; //No memory assigned
};
You need to allocate some valid memory to the pointer inside the structure to be able to put data in this.
Unless you do so, What you ar trying to do is attempting to write at some invalid address, which results in an Undefined Behavior, which luckiy in this case shows up as an exception.
Resolution:
struct CountCarrier
{
int *CurrCount; //No memory assigned
CountCarrier():CurrCount(new(int))
{
}
};
Suggestion:
Stay away from dynamic allocations as long as you can.
When you think of using pointers always think whether you really need one. In this case it doesn't really seem that you need one, A simple int member would be just fine.
You need to create the pointer. ie. carrier->CurrCount = new int;
*(carrier.CurrCount)
This is dereferencing the pointer carrier.CurrCount, but you never initialized it. I suspect this is what you want:
carrier.CurrCount = new int(2);
I seriously doubt that your program throws an exception at the line:
*(carrier.CurrCount) = 2;
While throwing an exception is certainly allowed behaviour, it seems much more likely that you encountered an access violation that caused the process to be killed by the operating system.
The problem is that you are using a pointer, but your pointer is not initialised to point at anything. This means that the result of the pointer dereference is undefined.
In this situation there does not seem to be any advantage to using a pointer at all. Your CurrCount member would work just as well if it was just a plain int.
If you are using C++, then you should encash its facilities. Instead of correcting your code, I am showing here that how the code should look like:
struct CountCarrier
{
int CurrCount; // simple data member
CountCarrier(int count) : CurrCount(count) {} // constructor
CountCarrier& operator ++ () // overloaded operator
{
++ CurrCount;
return *this;
}
};
We are overloading operator ++, because you have only one data member. You can replace with some named method also, like void IncrementCount().
CountCarrier carrier(2);
++ carrier;
As Als said, you need to provide some memory for the code to work.
But why make it so complicated? You don't need any pointers for the code you have to work. The "modern C++" way looks more like this:
struct CountCarrier
{
public:
CountCarrier(int currCount) : currCount(currCount) {}
void IncreaseCount() { ++currCount; }
int GetCount() const { return currCount; }
private:
int currCount;
};
int main()
{
CountCarrier carrier(2); // Initialize carrier.currCount to 2
carrier.IncreaseCount(); // Increment carrier.currCount to 3
}
Note how much cleaner and less error prone that is. Like I said, pick up a good introductory C++ book and read through it.