samedi 26 août 2017

C++ 11 - Modifying members of a struct in a vector of structs

I've searched elsewhere and here on SO for ways to do this, but didn't find any answers that addressed my issues and concerns.

Constraints:

  1. I'm using C++ 11 on an embedded device.
  2. I can't use std::string
  3. I can't use make_unique (but I can use unique_ptr with new)
  4. I can't use strcpy_s

Problems I'm having

The primary problem I'm having is that in the AvailableZones::upsertZone method I'd like to add a Zone to the vector if it doesn't already exist (using the name argument as a "key"). If it exists, I'd like to update the temperature and humidity members of the zone. The "adding" part works, however, the updating part does not.

The next issue I have is in the AvailableZones::findZone member. I'd like to be able to return a Zone such that the caller is not responsible for freeing/deleting the returned value.

Concerns:

Being new to C++, I'm pretty sure I'm not doing a lot of things the correct C++ 11 way. I'm open (eager actually) to any/all guidance. In the AvailableZones::findZone method I'd like return Zone I have rather than create a copy or use new/malloc. It looks like I'll need to use the regular for/while loop? I've seen some iterator code but it looks way to confusing/complicated but I'm not sure if using an iterator will solve this either.

Best Practice related questions:

  1. In the Zone struct's destructor, if I use delete, it causes and exception when I run the code. I'm obviously doing something wrong.
  2. In the Zone struct, can I make the name member a unique_ptr? If so, How? I've tried numerous ways but I'm not able to either get it to compile or work.
  3. Is there is better way to implement the Zone constructor?

The Code

I've put comments in code to explain the intent of the method as well as where I need help.

#include "stdafx.h"
#include <iostream>
#include <assert.h>
#include <memory>
#include <vector>

using namespace std;

struct Zone {
    Zone() {}
    Zone(const char* name, const float temperature, const float humidity)
    {
        auto bufferSize = snprintf(NULL, 0, "%s", name);
        this->name = (char*)malloc(bufferSize + 1);
        strcpy(this->name, name);
        this->temperature = temperature;
        this->humidity = humidity;
    }

    ~Zone() {
        // deleting name here causes an Exception
        //delete [] name;
    }

    char* name = nullptr;
    float temperature = 0.0f;
    float humidity = 0.0f;
};

class AvailableZones {
public:
    AvailableZones::AvailableZones() {
        m_zoneVec = std::vector<Zone>();
    }

    ~AvailableZones() {
    }

    /*
        Using Arguments, add a Zone to the private zoneVec member is it does not exist
        If is does exist (names of zones are unique and used as the "key"), then update
        the temperature and humidity of the existing zone with those in the arguments
    */
    void AvailableZones::upsertZone(const char *name, const float temperature, const float humidity) {

        for (auto zone : m_zoneVec) {
            if (strcmp(zone.name, name) == 0) {
                zone.temperature = temperature;
                zone.humidity = humidity;
                return;
            }
        }

        m_zoneVec.push_back(Zone(name, temperature, humidity));
    }

    /*
        Given a Zone name, find the zone and return it
        If a Zone with the given name does not exist
        return a nullptr
    */
    const Zone *AvailableZones::findZone(const char *name) const {

        for (auto zone : m_zoneVec) {
            if (strcmp(zone.name, name) == 0) {
                // I know this is not correct.
                // How would I do this, without using "new" and thus
                // forcing the caller to be responsible for deleting?
                return &zone;
            }
        }

        return nullptr;
    }

private:
    std::vector<Zone> m_zoneVec;
};


int main()
{
    auto livingRoom = "Living Room";
    AvailableZones availableZones;
    availableZones.upsertZone("Master Bedroom", 72.0f, 50.0f);
    availableZones.upsertZone(livingRoom, 70.0f, 48.0f);
    availableZones.upsertZone("Study", 68.0f, 46.0f);

    auto foundZone = availableZones.findZone(livingRoom);
    cout << foundZone->name << endl;
    cout << foundZone->temperature << endl;
    cout << foundZone->humidity << endl;

    assert(strcmp(livingRoom, foundZone->name) == 0);
    assert(70.0f == foundZone->temperature);
    assert(48.0f == foundZone->humidity);

    availableZones.upsertZone(livingRoom, 74.0f, 52.0f);

    assert(strcmp(livingRoom, foundZone->name) == 0);
    assert(74.0f == foundZone->temperature);
    assert(52.0f == foundZone->humidity);

    return 0;
}

Aucun commentaire:

Enregistrer un commentaire