首页 > 解决方案 > 类和代码抛出错误和奇怪的意外行为

问题描述

我正在做一个小项目。我遇到了一些问题,几周来我一直在努力解决这个问题。但是,我最终决定来到 SO,并在这里发布。我试图让我的两个功能正常工作:

Remove(...)并且SearchWithName(...),我正在使用基于 C++ 范围的 for 循环。但是,Remove 不会删除 Employee 在 Array 中的指针。我得到一些内存抛出错误。出于某种原因,即使名称匹配或不匹配,我仍然会匹配。奇怪的。我正在尝试使其部分匹配或完全匹配。

这是代码:https ://onlinegdb.com/B1Whf_eUP

int main(){
    
    EmployeeArray* empArr = new EmployeeArray[2]
    {
        Employee("Richard Johnson", "1801 E 10th St Pueblo, CO 81001"),
        Employee("David Paras", "15 Spring St Rear Peabody, MA 01960"),
    }
    
    std::cout << (empArr->SearchWithName("lol") != NULL ? "Employee found!" : "This employee couldn't be found!") << std::endl;
    
    empArr->remove(*(Employee("Richard Johnson", "1801 E 10th St Pueblo, CO 81001"))));
    
    return 0;
}

错误:

/usr/sbin/ld: /tmp/ccOVptof.o: 在函数main': jdoodle.cpp:(.text+0x90): undefined reference to Employee::Employee(std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string< char, std::char_traits, std::allocator >)' /usr/sbin/ld: jdoodle.cpp:(.text+0x174): undefined reference to `Employee::Employee(std::__cxx11::basic_string<char , std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >)' collect2: 错误: ld 返回 1 个退出状态

标签: c++c++11

解决方案


什么是编译器错误

你没有定义Employee(std::string name, std::string address). 你只是声明了。std::__cxx11::basic_string<char, std::char_traits, std::allocator>可能看起来很假,你可以把它换成std::string.

如果它编译你的代码会发生什么

EmployeeArray::employee指向一个动态分配的数组:

employee --> +---+---+---+---+---+-----+
             | 0 | 1 | 2 | 3 | 4 | ... |
             +---+---+---+---+---+-----+
             | E | E | E | E | E | ... |
             +---+---+---+---+---+-----+

当您执行 for 循环并找到要删除的员工时,您的ee外观如下:


employee --> +---+---+---+---+---+-----+
             | 0 | 1 | 2 | 3 | 4 | ... |
             +---+---+---+---+---+-----+
             | E | E | E | E | E | ... |
             +---+---+---+---+---+-----+
                   ^
                   |
                   ee

您可能希望这些Employeeee被删除,其他元素移到前面。

但是,delete使用这样的指针没有意义。C++ 数组几乎是愚蠢的,没有你想象的那么聪明。实际上,根据cppref ,您所做的是 C++ 中未定义的行为

  • ::(optional) delete expression (1)

  • ::(optional) delete[] expression (2)

  1. 销毁一个由 new 表达式创建的非数组对象

  2. 销毁由 new[] 表达式创建的数组

对于第一种(非数组)形式,表达式必须是指向对象类型的指针或上下文隐式可转换为此类指针的类类型,其值必须为空或指向由 new- 创建的非数组对象的指针表达式,或指向由 new 表达式创建的非数组对象的基本子对象的指针。如果 expression 是其他任何东西,包括如果它是通过 new-expression 的数组形式获得的指针,则行为未定义。

对于第二种(数组)形式,表达式必须是一个空指针值或先前通过new-expression的数组形式获得的指针值。如果 expression 是其他任何东西,包括如果它是通过 new-expression 的非数组形式获得的指针,则行为未定义。

C++ 编译器会将您delete视为尝试破坏指向Employeeee点,并取消分配该Employee. 由于您EmployeeArray::employee不是由单个创建的new,而是由创建的数组元素new[]delete因此可能无法成功销毁对象并取消分配内存。

未定义的行为意味着如果您这样做,任何事情都可能发生。您可能会看到错误,看到异常,看到核心转储,没有看到错误但得到错误的结果,或者一切正常而无需打扰。因此,未定义的行为极难调试,应尽一切努力避免。

解决方案

如果你坚持使用new[]手动创建数组,你可以使用new Employee*[]指针创建数组。然后手动分配给每个指针,其中Employees 创建于new Employee(). 那会像

employee --> +---+---+---+---+---+-----+
             | 0 | 1 | 2 | 3 | 4 | ... |
             +---+---+---+---+---+-----+
             | P | P | P | P | P | ... |
             +---+---+---+---+---+-----+

而且您将能够delete使用单个元素(不过,您需要手动将剩余的指针向左移动,delete不会为您处理)。

不回答的回答

代替处理脏内存的东西,你可以使用std::vector来存储你的数据,并使用std::find_if/std::remove_if进行数据操作。

要优雅地删除std容器中的元素,您可以使用std::remove_if+std::vector::erase组合。是一个例子。


推荐阅读