Класс C ++ с переменной-членом шаблона. и выход из памяти параметров - PullRequest
0 голосов
/ 17 июня 2020
struct PacketBase
{
    virtual ~PacketBase() {}

    template<class T> 
    const T& get() const
    {
        return static_cast<const PacketVal<T>&>(*this).val;
    }

    template<class T> 
    void set(const T& rhs)
    {
        return static_cast<PacketVal<T>>(*this).val = rhs;
    }
};


template <typename T>
struct PacketVal : public PacketBase
{
    T val;

    PacketVal(const T& rhs) : val(rhs) {}
    ~PacketVal() {}
};


class CResponsePacket
{
private:
    std::vector<std::pair<int, const PacketBase*>> m_vPacketData;

public:
    void addValue(int n, const PacketBase& packetData)
    {
        m_vPacketData.emplace_back(std::make_pair(n, &packetData));
    }

    void print()
    {
         for ( auto& data : m_vPacketData )
         {
              std::printf("%d - ", data.first);
              std::printf("%s\n", data.second->get<std::string>().c_str());
         }
    }
};

CResponsePacket имеет переменную-член класса шаблона.

int main()
{
    CResponsePacket packet;
    std::string strAAA("AAA");

    PacketVal<std::string> pVal(strAAA);
    packet.addValue(1, pVal);

    for ( int nIdx = 0; nIdx < 5; ++nIdx )
    {
        PacketVal<std::string> pp(strAAA);
        packet.addValue(nIdx + 1, pp);
    }

    packet.print();

    return 0;
}

Результат:

1 - AAA
1 -
2 -
3 -
4 -
5 -

Поскольку экземпляр находится в al oop, память уничтожается. Но это всего лишь пример, и на самом деле я должен использовать l oop. Как я могу решить эту проблему ...?

...................... ............. .....

1 Ответ

0 голосов
/ 17 июня 2020

Вы можете использовать std::shared_pointer или std::unique_ptr (в зависимости от вашего использования), и поэтому вектор будет выглядеть следующим образом:

std::vector<std::pair<int, std::shared_pointer<PacketBase>>> m_vPacketData;

И тогда метод addValue должен выглядеть вот так:

void addValue(int n, const PacketBase& packetData)
{
    m_vPacketData.emplace_back(
        std::make_pair(
             n, 
             std::make_shared<PacketBase>(packetData)
        )
    );
}

Это создаст копию packetData в куче и сохранит ссылку в общем указателе. Если вы не знаете, что делать с этой копией, вам необходимо определить новый конструктор в PacketBase

class PacketBase{
public: 
     PacketBase(PacketBase&& el): attr(std::move(el.attr))... {...}
}

, а затем переопределить addValue, который принимает ссылку на rvalue

void addValue(int n, PacketBase&& packetData)
{
    m_vPacketData.emplace_back(
        std::make_pair(
             n, 
             std::make_shared<PacketBase>(std::move(packetData))
        )
    );
}

А затем вызов правого addValue из main:

for ( int nIdx = 0; nIdx < 5; ++nIdx )
{
    PacketVal<std::string> pp(strAAA);
    packet.addValue(nIdx + 1, std::move(pp));
}

Или на самом деле просто:

for ( int nIdx = 0; nIdx < 5; ++nIdx )
    packet.addValue(nIdx + 1, PacketVal<std::string>(strAAA););

Это, очевидно, заставит вас переписать весь класс , потому что вы меняете тип атрибута ... Другой способ добиться этого - переключиться с

m_vPacketData.emplace_back(std::make_pair(n, &packetData));

на

m_vPacketData.emplace_back(std::make_pair(n, new PacketVal(packetData)));

Но вы должны не забыть удалить объекты в куче или будут утечки памяти

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...