C++ 在unordered_list中存储和传递引用而不是值

C++ Storing and passing references instead of values in an unordered_list

本文关键字:引用 unordered list 存储 C++      更新时间:2023-10-16

我有一些代码可以很好地编译和运行,但按值传递对象:

AssetRepository AssetRepositoryFactory::getAssetRepository(std::string clientId)
{
    std::unordered_map<std::string, AssetRepository>::iterator iterator = m_repositories.find(clientId);
    if ( iterator != m_repositories.end())
    {
        return iterator->second;
    }
    else
    {
        AssetRepository repository = AssetRepository(clientId);
        std::pair<std::string, AssetRepository> pair (clientId, repository);
        m_repositories.insert(pair);
        return repository;
    }
}

我打算让这段代码做的是通过引用传递,但这可能是一个相当常见的新手C++开发人员错误。所以我试图通过更改以下代码来通过引用传递:

AssetRepository& AssetRepositoryFactory::getAssetRepository(std::string clientId)
{
    std::unordered_map<std::string, AssetRepository&>::iterator iterator = m_repositories.find(clientId);
    if ( iterator != m_repositories.end())
    {
        return iterator->second;
    }
    else
    {
        AssetRepository repository = AssetRepository(clientId);
        std::pair<std::string, AssetRepository&> pair (clientId, repository);
        m_repositories.insert(pair);
        return repository;
    }
}

不幸的是,我收到此错误:

HEAP[CGF_flight_controller.exe]: Invalid allocation size - c3d9e9e0 (exceeded fffdefff)
First-chance exception at 0x000007FEFD24B3DD in CGF_flight_controller.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0000000002C6F4F0.
Microsoft Visual Studio C Runtime Library has detected a fatal error in CGF_flight_controller.exe.

那是如果我通过

AssetRepository repository = AssetRepositoryFactory::getInstance().getAssetRepository("clientId0");

或者,如果我打电话

AssetRepository &repository = AssetRepositoryFactory::getInstance().getAssetRepository("clientId0");

我得到

First-chance exception at 0x000007FEE72EAD7B (RTDynamics-vc11-md-64.dll) in CGF_flight_controller.exe: 0xC0000005: Access violation reading location 0x0000000000000028.
Unhandled exception at 0x000007FEE72EAD7B (RTDynamics-vc11-md-64.dll) in CGF_flight_controller.exe: 0xC0000005: Access violation reading location 0x0000000000000028.

我很难理解必须通过引用显式传递,因为我通常是 Java 开发人员。请有人帮我弄清楚吗?

这段代码是绝对错误的。

AssetRepository& function() {
    [...]
    AssetRepository repository = [...];
    [...]
    return repository; // by reference
    // but "repository" gets destroyed...
}

您正在返回对函数返回后不存在的对象的引用。 别这样。 这被称为"悬空引用"(将其放入Google)。 只能使用对现有对象的引用。

问题就在这里:

std::unordered_map<std::string, AssetRepository&>

容器的值应为可分配的。 但引用不可分配。 声明它们时,您只能初始化它们一次,并且您不能让它们稍后引用其他内容。

但是您有一些解决方案:

  • 像工作代码一样使用值。 并使用移动语义来降低复制值的成本。

  • 在映射中使用指向资产存储库的指针:

    std::unordered_map<std::string, AssetRepository*>

  • 使用引用包装器使引用可分配。

有关更多信息和解决方案,请查看此问题:为什么我不能制作引用向量?

最终找到了一个解决方案,并合并了关于悬空引用的评论和改用指针的建议。

AssetRepository* AssetRepositoryFactory::getAssetRepository(std::string clientId)
{
    std::unordered_map<std::string, AssetRepository>::iterator iterator = m_repositories.find(clientId);
    if ( iterator != m_repositories.end())
    {
        AssetRepository repository = iterator->second;
        return &(iterator->second);
    }
    else
    {
        AssetRepository repository = AssetRepository(clientId);
        std::pair<std::string, AssetRepository> pair (clientId, repository);
        m_repositories.insert(pair);
        return getAssetRepository(clientId);
    }
}