jlack
jlack

Reputation: 315

Object creation in static method is changing private member variables of other static object

To give a simple example of the problem I am having, consider a class that creates a link(like in a chain). Each link has a parent link except for the root link. The parent link of the root link is null.

#ifndef LINK_HPP
#define LINK_HPP

#include <memory>
#include <string>

//Link.hpp
class Link
{
    public:
        Link(const std::string &linkName, const Link *parentLink);
        Link(const std::string &linkName);
        const Link* getParentLink();
        ~Link();
        static Link* createRootLink(const std::string &linkName);
        static Link* getRootLink();

    private:
        std::string linkName;
        const Link *parentLink;
};

#endif
#include "Link.hpp"

Link* Link::createRootLink(const std::string &linkName)
{
    std::unique_ptr<Link> rootLink(new Link(linkName));
    return rootLink.get();
}

Link::Link(const std::string &linkName)
{
    this->linkName = linkName;
    this->parentLink = nullptr;
}

Link::Link(const std::string &linkName, const Link* parentLink)
{
    this->linkName = linkName;
    this->parentLink = parentLink;
}

Link::~Link()
{

}

const Link* Link::getParentLink()
{
    return this->parentLink;
}

In unit testing my code, I have created a helper class which defines functions useful for the testing. In HelperClass.hpp there is a static method that creates a shared pointer to a link and returns the raw pointer. Keep in mind this helper function is merely to reproduce a problem. I understand the method is kinda useless.

#include "Link.hpp"

class HelperClass
{
    public:
        static Link* createALink(const std::string &linkName, Link*     parentLink)
        {
            std::shared_ptr<Link> link(new Link(linkName, parentLink));

            return link.get();
        }
};

Alright now for the actual test that shows where the problem is.

#include "gtest/gtest.h"
#include "Link.hpp"
#include "HelperClass.hpp"

class ReferenceFrameTest : public ::testing::Test
{
    protected:

        virtual void SetUp()
        {
        }
        virtual void TearDown()
        {
        }

        Link* rootLink = Link::createRootLink("root");
        // Why does this call right here change the parentLink of rootLink!!
        Link* link1 = HelperClass::createALink("link1", rootLink);

    private:

};

TEST_F(ReferenceFrameTest, testRootLinkHasNullParent)
{
    // the parent link of rootLink should be nullptr or 0
    // this currently outputs 0x264f960
    std::cout << rootLink->getParentLink() << std::endl;

    // This fails if I create the Link* from HelperClass.hpp
    ASSERT_FALSE(rootLink->getParentLink());
}

The act of creating the pointer to a Link in HelperClass somehow is changing the parentLink of rootLink. Note that if instead I just instantiate a new Link on the stack, the parentLink of rootLink remains nullptr as it should. What am I missing here? Thanks so much in advance for the help!

Upvotes: 1

Views: 37

Answers (1)

aschepler
aschepler

Reputation: 72431

createRootLink returns a dangling pointer.

Link* Link::createRootLink(const std::string &linkName)
{
    std::unique_ptr<Link> rootLink(new Link(linkName));
    return rootLink.get();
}

The unique_ptr deletes its object when it goes out of scope, which is at the end of the createRootLink function. So that memory can be reused, or all sorts of other undefined behavior.

Upvotes: 1

Related Questions