繁体   English   中英

在std :: map中返回std :: vector

[英]Returning std::vector in std::map

我正在尝试返回地图内的std :: vector,但似乎无法正确处理。

下面的代码是我尝试过的代码,下面的代码是应该通过的测试

namespace grade_school {
class school {
    public:
        inline std::map<int, std::vector<std::string>> roster () {return 
MySchool;} 
        void add (std::string studentname , int grd);
        std::vector<std::string>& grade (int grd);
    private: 
        std::map<int,std::vector<std::string>> MySchool;
      };
}


void grade_school::school::add (std::string studentname, int grd){
MySchool[grd].push_back(studentname);
}

std::vector<std::string>& grade (int grd) {
return MySchool[grd];
};

TEST_CASE("grade_returns_the_students_in_that_grade_in_alphabetical_order")
{
grade_school::school school_;
school_.add("Franklin", 5);
school_.add("Bradley", 5);
school_.add("Jeff", 1);

const auto actual = school_.grade(5);

const vector<string> expected{"Bradley", "Franklin"};
REQUIRE(expected == actual);

}

我期望返回类型将是映射内包含的向量,但是我得到的编译器错误是错误C2065:'MySchool':未声明的标识符

我希望返回类型将是包含在地图中的向量。

这留下解释的余地,这取决于你如何理解这句话,这已经如此-或不...

std::vector<std::string> grade(int grd);

在C ++中,我们说的是返回“按值”。 您将确切获得映射中的值。 但是按值返回意味着您可以得到一个副本。 如果现在修改返回值,则实际上是修改副本,而不是映射中的向量。

std::vector<std::string>& grade(int grd);
//                      ^ note the ampersand!

“与”号表示我们只返回了对地图中向量的引用(在这种情况下,其行为类似于指针),现在您可以通过引用直接修改地图中的向量:

grade(7).push_back("seven");

为了完整性:指针:

std::vector<std::string>* grade(int grd) { return &mySchool[grd]; }
// need address-of operator:                      ^

grade(7)->push_back("seven");

通常,人们更喜欢引用,但是该指针在某些特定情况下可能很有用,例如,您可以返回nullptr (对于引用来说是不可能的),以表示对于某些特定输入没有合适的向量。

在某些用例中,您可能不想允许修改返回的向量。 通过副本返回可以避免这种情况,但是副本可能会很昂贵。 为了避免复制并仍然不允许修改,可以按const引用返回:

std::vector<std::string> const& grade(int grd);

诚然,用户可能const_cast了const,但是那是用户违反了合同(将const退还给别人就意味着撕毁:“不要修改它,如果这样做,那就是你的错!”)。

使用引用类型作为返回值:

 std::map<int,std::vector<std::string>> MySchool;
 std::vector<std::string>& grade (int grd) {
   return MySchool[grd];
 }

由于性能,最好将引用与容器和其他足够大的数据对象一起使用。 这样可以最大程度地减少由数据重复引起的内存操作。

如果您打算在封装此映射的方法或对象之外修改向量,则非const引用方法会很好。 这是一个简单的解决方案,始终为您提供实际数据并允许修改。

更好的方法是将数据的修改封装在类(或api函数集)的方法中,以避免用户进行意外的和未经验证的修改。 为此,请使用返回类型const reference

const std::vector<std::string>& grade (int grd)

如果您确实需要那种情况的数组副本,则可以通过表达sintax来简单地完成。 例如,分配给值而不是引用:

// ref - is const reference to some array returned by function
const std::vector<std::string>& ref = grade(10)

// array - is a full copy of array pointed by reference returned from function
std::vector<std::string> array = grade(10)

当您返回对容器或某些数据的引用时,您需要了解用户代码保存引用的问题,并且该引用可能会多次使用。 在此期间,取决于您的容器或代码如何管理内存中的数据,这可能会带来问题。 因此,可能会释放先前返回的引用所引用的内存中的数据。 在引用变为错误的内存之前返回。 但是用户代码可能会使用该引用,并导致访问冲突或某些未定义的行为。

即使您的对象保证在所有对象生存期内,方法返回的引用都将存在。 与对象本身相比,引用在用户代码中的保存时间可能更长。 因此,根本无法保证。

但是,我们可以使用简单的规则只是不将引用保存在变量中。 只需在函数始终调用同一表达式中使用数据:

  grade(10).length()
  std::accumulate(grade(10).begin(), grade(10).end(), 0)

但是,用户可能不知道或忘记此规则。

当然,您的函数必须始终返回对现有数据的引用。 例如,如果在指定索引处没有此类数组,则需要在指定索引处创建适当的数组并将其用于返回。

当然,函数一定不能返回对函数体中声明的任何非静态变量的引用,因为在函数返回之后和使用返回值之前,所有非静态变量都将被销毁。 保证应用程序崩溃。 在这种情况下,请使用按值返回。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM