-2

Array:

#ifndef ARRAY_H
#define ARRAY_H

#include <bits/stdc++.h>
using namespace std;

namespace Maifee{

class Value;

class Array {
public:
    Array();
    vector<Value> _elements;
};

}

#endif // ARRAY_H

Object :

#ifndef OBJECT_H
#define OBJECT_H


#include <bits/stdc++.h>
#include "value.h"
using namespace std;

namespace Maifee{

class Value;

class Object{
public:
    Object();
    map<string, Value> _members;
};

}


#endif // OBJECT_H

Value :

#ifndef VALUE_H
#define VALUE_H

#include <bits/stdc++.h>
#include "array.h"
#include "object.h"
using namespace std;

namespace Maifee{
    
class Array;
class Object;

class Value {
public:
    Value();
    Value(Object *__object);
    Array *_array;
    Object *_object;
};

}

#endif // VALUE_H

I'm learning C++ at my best. With my teeny tiny knowledge in C++, I am trying to write some code. First reason I'm moving C++, pointers take a lot's of time.

Here I'm writing these code, where forward-declaration is necessary, and due to this even after using forward-declaration and ifndef, I need to use pointer, which I really don't want.

Can anyone really help me with this, how can I remove circular dependency??

Do I need to go back to C?

When using pointer I faced many problems such as, I have just one key-value pair in my map, but in the next line size becomes a very large number, out of nowhere.

Code inside main :

    Object object=Object();
    cout << "pop obj tem len" << object._members.size() << endl; //gives 0 as expected
    object._members = members;
    cout << "pop obj tem len" << object._members.size() << endl; //gives the expected number
    Value val=Value(&object);
    cout << val._object->_members.size() << "size here" << endl; //gives a random number

Constructor for Value with Object parameter :

Value::Value(Object *__object)
{
    Object object;
    object._members.insert(__object->_members.begin(), __object->_members.end());
    _object = &object;
}
Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
  • 5
    Important reading: [Why should I not #include ?](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) and [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). Especially when used together _and_ in a header this is a nice way of creating really nasty bugs and increase compile time by an order of magnitude. – Lukas-T Sep 01 '20 at 19:34
  • 2
    Just another proof that `#include ` and `using namespace std;` are not acceptable even in the so called "competitive programming". People pick bad habits from the very beginning and then stick to them. – Evg Sep 01 '20 at 19:37
  • 2
    What are you asking exactly? I couldn't follow you line of thought. You tried pointers, it didn't work out, you don't know if you should stick to C... But what does that have to do with the code you pasted here? What's the actual problem you want help with? – StoryTeller - Unslander Monica Sep 01 '20 at 19:43
  • @MaifeeUIAsad "*When using pointer I faced many problems such as, I have just one key-value pair in my map, but in the next line size becomes a very large number, out of nowhere.*" - then you are doing something else wrong, outside of the code you have shown. But we can't see what that is. Please provide a [mcve]. You are likely accessing an invalid pointer. – Remy Lebeau Sep 01 '20 at 19:58
  • @remy just added two constructors with map as parameter and object as parameter... And the code is in main function. – Maifee Ul Asad Sep 01 '20 at 20:04
  • @MaifeeUlAsad Again, please [edit] your question to provide a [mcve]. We can't see what you are actually doing. – Remy Lebeau Sep 01 '20 at 20:06
  • Slightly puzzled about the "should I go back to C" aspect of the question, @MaifeeUlAsad . What you are trying to do here would be even messier ball of pointers in C. – user4581301 Sep 01 '20 at 20:11
  • @RemyLebeau please check out the post again, I have updated everything... – Maifee Ul Asad Sep 02 '20 at 07:35

1 Answers1

1

You can't avoid the forward-declarations and pointers in this situation.

class Object has a map<string, Value> member, and class Array has a vector<Value> member. Which means Value must be a fully-defined, complete type by the time Object and Array are being compiled, as map and vector need to know the total size of their element types. If Value were to have non-pointer Array and Object members, then Object and Array would need Value to be a complete type, but Value would need Object and Array to be complete types. Catch-22!

So, you have to use forward declarations and pointers/references for the Value members in order to make this kind of circular referencing work properly, since pointers/references to incomplete types are allowed.


UPDATE: In your Value constructor that takes an Object* parameter, you are setting the _object member to point at a local Object instance that goes out of scope and is destroyed when the constructor exits, thus leaving _object dangling. That is why the subsequent val._object->_members.size() expression in main() produces garbage (you are lucky the code didn't crash outright) - val._object is pointing at invalid memory, so its members is not a valid map object and so reading its size() is undefined behavior. That goes right back to the original comment I posted:

You are likely accessing an invalid pointer.

To solve this, depending on your actual design goal, the Value constructor needs to either:

  • construct a new Object dynamically, which will have to be delete'd later. You will also have to provide a proper copy constructor and copy assignment operator:
Value::Value()
{
    _object = NULL;
    _array = NULL;
}

Value::Value(Object *__object)
{
    _object = new Object;
    _array = NULL;
    if (__object)
        _object._members = __object->_members;
}

Value::Value(const Value &__value)
{
    _object = new Object;
    _array = NULL;
    if (__value._object)
        _object._members = __value._object->_members;
}

Value::~Value()
{
    delete _object;
}

Value& Value::operator=(const Value &__value)
{
    if (&__value != this)
    {
        Value tmp(__value);
        std::swap(_object, tmp._object);
        std::swap(_array, tmp._array);
    }
    return *this;
}
  • simply store the Object* pointer it is given:
Value::Value(Object *__object)
{
    _object = __object;
    _array = NULL;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Is there any way I can define the shape of those objects in all headers... I just want to avoid pointers ... – Maifee Ul Asad Sep 01 '20 at 19:53
  • "*I just want to avoid pointers*" - why? If you are not comfortable using pointers, then you shouldn't be using C++ at all. Pointers are a core and important part of the C++ language. – Remy Lebeau Sep 01 '20 at 19:55
  • https://pastebin.com/ykH20JDs. At the first line it says the size I gave to it, on the next line it is just a random number... Map filled with garbage values... – Maifee Ul Asad Sep 01 '20 at 19:59
  • @MaifeeUlAsad please don't post the code on another site, [edit your question](https://stackoverflow.com/posts/63694258/edit) instead and put the relevant code there. SO questions are meant to be self-contained, and external links break over time. In any case, `Object object=Object(members)` and `Value val=Value(&object)` do not compile, as `Object` and `Value` have no such constructors in the code you have shown so far. – Remy Lebeau Sep 01 '20 at 20:07
  • please check out the post again, I have updated everything... – Maifee Ul Asad Sep 02 '20 at 07:35
  • maybe it works, cause I had a stack of `stack values;`, where I used to push and pop values, I received...`Value val = Value(__value_int);_values.push(val);`.. now it gives me runtime error... maybe due to that operator.. i don't know,but thanks... i tried `try/catch cerr/cout`, which gives me nothing.. – Maifee Ul Asad Sep 02 '20 at 10:46
  • 1
    @MaifeeUlAsad bad things happen when you dont follow the [Rule of 3/5/0](https://en.cppreference.com/w/cpp/language/rule_of_three) properly. – Remy Lebeau Sep 02 '20 at 14:54