1

I have a class that I am trying to set a value to if it is correctly inserted into a set. Here is that class.

class flow {
    std::string source, dest, protocol, startTime; //
public:
    flow() {}
    flow(std::string & s, std::string & d, std::string p) :
            source(s), dest(d), protocol(p) {}
        bool operator==(const flow& rhs) const;
        bool operator<(const flow& rhs) const;
        bool setFields(std::string &, std::string &, std::string &);
        std::string getSource() const;
        std::string get_startTime() const;
            //other getters not shown
        void set_startTime(std::string &);
            //other setters not shown
        virtual ~flow();
        std::string createKey() const;
};

bool flow::setFields(std::string & srcArg, std::string & destArg,
    std::string & protocolArg) {
    source = srcArg;
    dest = destArg;
    protocol = protocolArg;
    return true;
}


void flow::set_startTime(std::string & a) {
    startTime = a;
}

I have a set of this class set<flow> flows;. I insert this flow into a set. If it it fails to insert, I know I am already tracking this flow, but if not I want to set its start time.

flow currentFlow;
//...
protocol = string("TCP");
currentFlow.setFields(source, dest, protocol);
key = createKeyFromFlow(currentFlow);
ret = flows.insert(currentFlow); // see if we can insert this flow
if (ret.second == false) {
        inserted = false;
        // we failed to insert
        it = ret.first; // "it" now points to element already in the set
} else {
        string stringTS;
        std::stringstream strstream;
        //convert to string and store
        strstream << currentTimeStamp;
        strstream >> stringTS;
        cout << stringTS << endl;
        currentFlow.set_startTime(stringTS);
        //sanity check to assert the value was set
        cout << currentFlow.get_flow() << endl;
}

The sanity check passes, and the value is print. However, later as I am displaying these flows the value is no longer set. How can I persist this value? Is this currentFlow not the same flow that is persisted inside of my set?

Let me know if you need more information, I didn't want to post too much code, but enough to diagnose the problem.

nook
  • 2,378
  • 5
  • 34
  • 54
  • related: a proper implementation of your `operator <` is *critical* for that set to operate correctly. Make *sure* it is implementing a proper [strict weak ordering](http://en.wikipedia.org/wiki/Weak_ordering). – WhozCraig Mar 08 '14 at 01:26
  • I can post it if necessary, but I am able to retrieve the correct flow, and say whether I am tracking it already or not. The problem is the persistence. – nook Mar 08 '14 at 01:32

1 Answers1

2

The problem is that set::insert creates a copy of the flow object. So any changes you make to currentFlow after

 ret = flows.insert(currentFlow); 

have no influence on the object that is actually stored in the set.

EDIT: As Matt McNabb mentions below, one should be aware that this problem cannot be fixed by simply modifying of the copy stored in the flow set, as this would invalidate its key (read e.g. what happens when you modify an element of an std::set? for further information)

Community
  • 1
  • 1
MikeMB
  • 20,029
  • 9
  • 57
  • 102
  • 2
    Building on this a bit, you should be very careful if you try to "edit" in-place the object that is in the set; because if you do something that changes what its ordering is, then the set will be in an invalid state, and malfunction thereafter. Consider using a `map` instead of a `set`, if the "key" can be separated from the "value" parts of your flow. – M.M Mar 08 '14 at 02:04
  • @MattMcNabb So I can't modify the inserted one either? Or am I misunderstanding that link? And can I do this if I was to use a set instead of a map? – nook Mar 08 '14 at 02:33
  • @publ1c_stat1c There is a reason C++11 made [`std::set`](http://en.cppreference.com/w/cpp/container/set) iterators `const`. – WhozCraig Mar 08 '14 at 07:06