 
                            ...
Using the same class definitions as the noncompliant code example, this compliant solution modifies the definition of f() to require raw pointers to the object, removing the slicing problem:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| // ... restRemainder of code unchanged ... void f(const Employee *e) { if (e) { std::cout << *e; } } int main() { Employee coder("Joe Smith"); Employee typist("Bill Jones"); Manager designer("Jane Doe", typist); f(&coder); f(&typist); f(&designer); } | 
This compliant solution also complies with EXP34-C. Do not dereference null pointers in the implementation of f(). With this definition, the the program correctly outputs :the following.
| Code Block | 
|---|
| Employee: Joe Smith Employee: Bill Jones Manager: Jane Doe Assistant: Employee: Bill Jones | 
...
An improved compliant solution, which does not require guarding against null pointers within f(), uses references instead of pointers:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| // ... restRemainder of code unchanged ... void f(const Employee &e) { std::cout << e; } int main() { Employee coder("Joe Smith"); Employee typist("Bill Jones"); Manager designer("Jane Doe", typist); f(coder); f(typist); f(designer); } | 
...
Both previous compliant solutions depend on consumers of the Employee and Manager types to be declared in a compliant manner with the expected usage of the class hierarchy. This compliant solution ensures that consumers are unable to accidentally slice objects by removing the objects' ability to copy-initialize an object that derives from Noncopyable. If copy-initialization is attempted, as in the original definition of f(), the program is ill-formed and a diagnostic will be emitted. However, such a solution also restricts the Manager object from attempting to copy-initialize its Employee object, which subtly changes the semantics of the class hierarchy.
...
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <iostream>
#include <string>
class Noncopyable {
  Noncopyable(const Noncopyable &) = delete;
  void operator=(const Noncopyable &) = delete;
  
protected:
  Noncopyable() = default;
};
class Employee : Noncopyable {
  // Remainder of the definition is unchanged.
  std::string name;
  
protected:
  virtual void print(std::ostream &os) const {
    os << "Employee: " << get_name() << std::endl;      
  }
  
public:
  Employee(const std::string &name) : name(name) {}
  const std::string &get_name() const { return name; }
  friend std::ostream &operator<<(std::ostream &os, const Employee &e) {
    e.print(os);
    return os;
  }
};
 
class Manager : public Employee {
  const Employee &assistant; // Note: ThisThe definition of Employee has been modified.
  // Remainder remainingof the definition is unchanged.
protected:
  void print(std::ostream &os) const override {
    os << "Manager: " << get_name() << std::endl;
    os << "Assistant: " << std::endl << "\t" << get_assistant() << std::endl;      
  }
  
public:
  Manager(const std::string &name, const Employee &assistant) : Employee(name), assistant(assistant) {}
  const Employee &get_assistant() const { return assistant; }
};
 
// If f() were declared as accepting an Employee, the program would be
// ill-formed because Employee cannot be copy-initialized.
void f(const Employee &e) {
  std::cout << e;
}
int main() {
  Employee coder("Joe Smith");
  Employee typist("Bill Jones");
  Manager designer("Jane Doe", typist);
  
  f(coder);
  f(typist);
  f(designer);
} | 
...
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| // In addition to the #includes from the previous example#include <iostream> #include <string> #include <vector> void f(const std::vector<Employee> &v) { for (const auto &e : v) { std::cout << e; } } int main() { Employee typist("Joe Smith"); std::vector<Employee> v{typist, Employee("Bill Jones"), Manager("Jane Doe", typist)}; f(v); } | 
...
This compliant solution uses a vector of std::unique_ptr objects, which eliminates the slicing problem:.
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| // In addition to the #includes from the previous example#include <iostream> #include <memory> #include <memory><string> #include <vector> void f(const std::vector<std::unique_ptr<Employee>> &v) { for (const auto &e : v) { std::cout << *e; } } int main() { std::vector<std::unique_ptr<Employee>> v; v.emplace_back(new Employee("Joe Smith")); v.emplace_back(new Employee("Bill Jones")); v.emplace_back(new Manager("Jane Doe", *v.front())); f(v); } | 
...
Slicing results in information loss, which could lead to abnormal program execution or denial-of-service attacks.
| Rule | Severity | Likelihood | Detectable | 
|---|
| Repairable | Priority | Level | |
|---|---|---|---|
| OOP51-CPP | Low | Probable | No | 
| No | 
| P2 | L3 | 
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| CodeSonar | 
 | LANG.CAST.OBJSLICE | Object Slicing | ||||||
| Helix QAC | 
 | C++3072 | |||||||
| Parasoft C/C++test | 
3072, 3073
| 
 | CERT_CPP-OOP51-a | Do not slice derived objects | |||||||
| Polyspace Bug Finder | 
 | CERT C++: OOP51-CPP | Checks for object slicing (rule partially covered) | ||||||
| PVS-Studio | 
 | V1054 | 
Related Vulnerabilities
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
| SEI CERT C++ Coding Standard | ERR61-CPP. Catch exceptions by lvalue reference | 
| SEI CERT C Coding Standard | 
Bibliography
| [Dewhurst | 
| 2002] | Gotcha #38, "Slicing" | 
| [ISO/IEC 14882-2014] | Subclause 12.8, "Copying and Moving Class Objects" | 
| [Sutter | 
| 2000] | Item 40, "Object Lifetimes—Part I" | 
...
...