In c++, creating an object without calling a constructor like this. Does this count as defined behavior? (Disregard the unfreed heap memory)
class Foo {
public:
int *ptr;
int a, b;
Foo() { ptr = new int{}; }
~Foo() { delete ptr; }
void set(int a_, int b_) {a = a_; b = b_;}
void print() { std::cout << *ptr << a << b; }
};
int main() {
char *array[sizeof(Foo)]; // note the pointer
*((int**)array) = new int{3};
((Foo*)array)->set(1, 2);
((Foo*)array)->print(); // 312
}
You are building a memory block that can hold the data for the object, but that is not an object.
An object consist of potentially a lot more than that slice of memory, and what exactly more is up to the compiler. It could be nothing more, but it could be a lot of other things.
Related
i tried to change cost1 field through C class but it didn't work. how can i access and change cost1(inside M class) through C class.
i am getting null pointer error and it has shown inside setM function.
class M {
protected:
int cost1;
public:
M() {}
M(int c1) :cost1(c1) {}
int getCost1() { return cost1; }
void setCost1(int c1) { cost1 = c1; }
};
class P {
protected:
M* _m;
public:
void setM(M m) {
_m = &m;
}
M getM() {
return *_m;
}
};
class C {
protected:
std::shared_ptr<P> _p;
M _m;
public:
C(M m) {
_m = m;
}
void setP(std::shared_ptr<P> p) {
_p = p;
}
void applyM() {
std::cout << _p->getM().getCost1() << std::endl;
_p->getM().setCost1(11);
std::cout << _p->getM().getCost1() << std::endl;
}
};
int main()
{
std::shared_ptr<P> p1;
M m1(5);
std::shared_ptr<C> c1 = std::make_shared<C>(m1);
p1->setM(m1);
c1->setP(p1);
c1->applyM();
}
In the following function
void setM(M m) {
_m = &m;
}
You are passing m by value. This makes a local copy of a passed variable. Then you take address of the copied (local!) variable, which gets destroyed once the function finishes.
You need to pass either by reference or by pointer instead.
There's a problem in your class P. Its constructor takes an M object, by value. This means that when it is called, a temporary copy of the caller's M object is created and passed to it. The address of this temporary is then stored in the protected member _m. After the constructor finishes executing, the temporary copy is destroyed, the _m pointer is invalid, and accessing it will cause undefined behavior.
The solution is to pass the address that you want to store.
class P {
protected:
M* _m;
public:
void setM(M* p) {
_m = p;
}
M getM() {
return *_m;
}
};
There's also a problem in main
std::shared_ptr<P> p1;
...
p1->setM(m1);
You're dereferencing the pointer p1 without ever initializing it. Again, this is going to cause undefined behavior.
Why does the following code print 0, but if you comment out "std::string my_string" it prints 1?
#include <stdio.h>
#include <iostream>
class A {
public:
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
class B : public A {
public:
int foo() {
return 1;
}
};
int main()
{
A* a;
if (true) {
B b;
a = &b;
}
std::cout << a->foo() << std::endl;
return 0;
}
I also understand that changing std::string to std:string* also causes the code to print 1, as does removing the if-statement, though I don't understand why any of that is true.
EDIT: This seems to be due to a dangling pointer. Then what's the standard pattern in C++ to do something like this in Java:
Animal animal;
boolean isDog = false;
// get user input to set isDog
if (isDog) {
animal = new Dog();
} else {
animal = new Cat();
}
animal.makeNoise(); // Should make a Dog/Cat noise depending on value of isDog.
Problem
The program has Undefined Behaviour. b is only in scope inside the body of the if. You can't count on logical results when accessing a dangling pointer.
int main()
{
A* a;
if (true) {
B b; // b is scoped by the body of the if.
a = &b;
} // b's dead, Jim.
std::cout << a->foo() << std::endl; // a points to the dead b, an invalid object
return 0;
}
TL;DR Solution
int main()
{
std::unique_ptr<A> a; // All hail the smart pointer overlords!
if (true) {
a = std::make_unique<B>();
}
std::cout << a->foo() << std::endl;
return 0;
} // a is destroyed here and takes the B with it.
Explanation
You can point a at an object with a dynamic lifetime
int main()
{
A* a;
if (true) {
a = new B; // dynamic allocation
} // b's dead, Jim.
std::cout << a->foo() << std::endl;
delete a; // DaANGER! DANGER!
return 0;
}
Unfortunately delete a; is also undefined behaviour because A has a non-virtual destructor. Without a virtual destructor the object pointed at by a will be destroyed as an A, not as a B.
The fix for that is to give A a virtual destructor to allow it to destroy the correct instance.
class A {
public:
virtual ~A() = default;
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
There is no need to modify B because once a function is declared virtual, it stays virtual for its children. Keep an eye out for final.
But it's best to avoid raw dynamic allocations, so there is one more improvement we can make: Use Smart pointers.
And that brings us back to the solution.
Documentation for std::unique_ptr
Documentation for std::make_unique
I use shared_ptr to handle pointers like this in my program.
struct D
{
D() { std::cout << "D ctor\n"; }
~D() { std::cout << "D dtor\n"; }
};
struct CC
{
private:
std::vector<std::shared_ptr<D>> pDs;
static std::shared_ptr<CC> pC;
CC() { std::cout << "C ctor\n"; };
public:
static std::shared_ptr<CC> GetInstance()
{
if (nullptr == pC)
{
pC = std::shared_ptr<CC>(new CC);
return pC;
}
return pC;
}
void Save(std::shared_ptr<D> d)
{
pDs.emplace_back(d);
std::cout << "saved b\n";
}
void Delete(int i)
{
pDs.erase(pDs.begin() + i);
}
int Size() { return pDs.size(); }
~CC() { std::cout << "C dtor\n"; }
};
std::shared_ptr<CC> CC::pC(nullptr);
struct Caller
{
void Init()
{
std::shared_ptr<D> d = std::shared_ptr<D>(new D());
CC::GetInstance()->Save(d);
}
int Size()
{
return CC::GetInstance()->Size();
}
};
struct Deletor
{
void Delete(int i)
{
CC::GetInstance()->Delete(i);
}
};
Using this in a console application, there is no error.
My question is,
if I save or clone many instances of shared_ptr in 2 or more different map/vector objects (shared_ptr are used as their values) as shown above, and at some point I would want to remove 1 or more instances of them (via e.g erase(key/iterator)) of one object, how can I manipulate their twins that are stored in other objects?
For example,
MAP_A = MAP_B = {key,shared_ptr}
MAP_A.erase(key_i);
//what should I do with MAP_B(key_i)?
how can I manipulate their twins that are stored in other objects?
No need. That's the entire point for having a shared_ptr.
As per std::shared_ptr:
std::shared_ptr is a smart pointer that retains shared ownership
of an object through a pointer. Several shared_ptr objects may own
the same object.
It has a reference counting mechanism that tracks how many pointers are sharing the "shared" object.
leaks in destructors
Once reference count is zero that's the time the shared object is freed.
This guarantees that there will be at most no leaks.
I am having a trouble of putting multiple class objects as member of another class. To be more specific: lets assume we have 2 classes, A and B and class A is nested. I want the main function to have an array with 3 objects of class B. The first object will have 2 objects of class A, the second object will have 5 objects of class A and the third object will have 7 objects of class A. How can i do that? Below is one of my thoughts:
Class A{
private:
int variable;
public:
A(){
cout<< A created! <<endl;
}
~A(){
cout<< A destructed! <<endl;
}
};
Class B{
private:
A array[6]; //It will always create 6 elements of class A...
public:
B(){
cout<< B created! <<endl;
}
~B(){
cout<< B destructed! <<endl;
}
};
int main(){
B* array[3];
for (i = 0 ; i <= 2 ; i++)
{
array[i] = new B(); //Every B element in array have 6 elements of class A
}
}
Thanks in advance!
If you can't use vectors.. (which you should).. here is a working example that shows what you want to do with arrays and manual memory management. https://ideone.com/KihmON
Note: there is no error handling in here. If this was your program it's very unlikely new will ever fail, but for larger objects it can. If you thrown an error in main before your delete statements, those objects will never get deleted. That is why vector is preferred, in the case of errors, it will get cleaned up when it leaves scope no matter what.
#include <iostream>
class A
{
private:
int variable;
public:
A()
{
std::cout << "A created!" << std::endl;
}
~A()
{
std::cout << "A destructed!" << std::endl;
}
};
class B
{
private:
size_t arrayOnHeapSize; // size of array on heap
A* arrayOnHeap; // memory must be allocated before this is used.
public:
B(size_t arrSize) :
arrayOnHeapSize(arrSize)
{
arrayOnHeap = new A[arrSize]; // must deallocate memory manually, use "delete[]" arrays of objects
std::cout<< "B created with size" << arrSize << '!' << std::endl;
}
~B()
{
delete[] arrayOnHeap; // must deallocate memory manually
std::cout << "B destructed! Wouldn't have had to do memory management manually if I had used a vector!" << std::endl;
}
B(const B&) = delete; // If you need to make a copy, you'll have to make a copy constructor that performs a deep copy or adds some (ugly) reference counting logic. Could also opt to implement a move constructor. If you copied this as is, the pointer will get copied, one B will get destructed freeing the memory, then the other B will have a dangling pointer and try to free that upon destruction. No good.
};
int main()
{
B* arrayOfB[3];
arrayOfB[0] = new B(2);
arrayOfB[0] = new B(5);
arrayOfB[0] = new B(7);
delete arrayOfB[0]; // must deallocate manually, using "delete" instead of "delete[]" because these are each 1 object, not arrays.
delete arrayOfB[1];
delete arrayOfB[2];
// Don't need to delete arrayOfB as it is a local on the stack and will be taken care of as the function exits.
}
You can make B a parameterised type (I think that's the correct term):
template<int a>
class B {
A array[a];
};
int main() {
B<2> b1;
B<5> b2;
B<7> b3;
}
However they can't be in an array as B<2> is a different type to B<7> etc.
Sample program:
#include <memory>
#include <iostream>
class D;
class C {
public:
C();
void callD();
void replaceD(D* d);
private:
std::shared_ptr<D> d;
};
class D {
public:
D(C* c);
void call();
private:
virtual void print();
C* c;
};
C::C() : d(new D(this)) {}
void C::callD() {
d->call();
}
void C::replaceD(D* d) {
this->d = std::shared_ptr<D>(d);
}
D::D(C* c) : c(c) {}
void D::call() {
c->replaceD(new D(c));
print();
}
void D::print() {
std::cout << "Hello, World!" << std::endl;
}
int main(void) {
auto c = new C();
c->callD();
return 0;
}
(With gcc: g++ -std=c++11 tmp.cpp -o tmp && ./tmp)
What happens:
C::callD() calls d->call()
D::call() calls c->replaceD()
C::replaceD() reassigns the C’s d pointer, causing the old d to be deleted
D::call() attempts to call the virtual method print() – but the current d instance was deleted by C::replaceD()!
Segmentation fault
Workaround: Insert auto d_ = d; in C::callD() so that the shared_ptr isn’t deleted until C::callD() finishes. But that looks suspiciously like an optimizeable unused variable (though g++ doesn’t seem to remove it even on -O3).
Shouldn’t the refcount be increased on any ptr->method() call until method() returns, to avoid this problem where method’s this is prematurely deleted?
Shouldn’t the refcount be increased on any ptr->method() call until method() returns, to avoid this problem where method’s this is prematurely deleted?
No. The semantics of std::shared_ptr are strictly pointer references, not function calls. The object needs to be referenced in another object or on the stack. You're deleting the reference.
void C::replaceD(D* d) {
this->d = std::shared_ptr<D>(d);
}
This code might as well be delete this instead of c->replaceD(new D(c)).
void D::call() {
c->replaceD(new D(c));
print();
}
I'm not sure what you're trying to do, but if you need to keep the reference to D alive, you can rewrite C::replaceD.
std::shared_ptr<D> C::replaceD(D* d) {
std::shared_ptr<D> old = this->d;
this->d = std::shared_ptr<D>(d);
return old;
}
Then rewrite D::call.
void D::call() {
std::shared_ptr<D> prev = c->replaceD(new D(c));
prev->print();
}
You can pass a std::shared_ptr reference into C::replaceD that can be given ownership of Cs current D before it is deleted.
void C::replaceD(D* d, std::shared_ptr<D>& tmp)
{
tmp.swap(this->d);
this->d = std::shared_ptr<D>(d);
}
and then D can keep itself alive until the end of the D::call
void D::call()
{
std::shared_ptr<D> tmp {};
c->replaceD(new D(c), tmp);
print();
}
I have to say though that your code seems poorly designed to me, and I would first consider if there's not a better design that would avoid this issue entirely.