Skip to main content

Secondary navigation

  • Downloads
  • Integrations
  • Blog
  • Company
    • About Us
    • Team
    • Culture
    • Careers
    • Partners
    • Press
    • Events
    • Security & Compliance
  • Contact
    • Contact Us
    • Request Support
    • Subscribe
  • Language
    • English
    • 日本語
    • 简体中文
    • 한국어
Home
Perforce

Main Navigation - Mega Menu

  • Products

    Main Navigation - Mega Menu

    • Explore Products
    • All Products
    Helix Core
    Version Control
    Helix TeamHub
    Code Hosting for Git, SVN, Hg
    Methodics IPLM
    IP Lifecycle Management
    Gliffy
    Diagramming
    JRebel
    Java Application Development
    Helix DAM
    Digital Asset Management
    Helix Core
    Version Control
    Helix TeamHub
    Code Hosting for Git, SVN, Hg
    Methodics IPLM
    IP Lifecycle Management
    Gliffy
    Diagramming
    JRebel
    Java Application Development
    Helix DAM
    Digital Asset Management
  • Solutions

    Main Navigation - Mega Menu

    • Explore Solutions
    • Solutions Overview

    Main Navigation - Mega Menu

    • By Need
    • By Industry

    Main Navigation - Mega Menu

    • Application Lifecycle Management
    • Agile Project Management
    • Diagramming
    • DevOps
    • Version Control
    • IP Lifecycle Management
    • Java Application Development
    • Web & Mobile App Testing
    • Codeless Selenium Automation
    • Static Analysis & SAST
    • Audit & Compliance
    • API Management
    • Open Source Support
    • Enterprise PHP
    • HPC Debugging
    • Development Tools & Libraries

    Main Navigation - Mega Menu

    • Aerospace & Defense
    • Automotive
    • Embedded Systems
    • Semiconductor
    • Energy
    • Financial
    • Game Development
    • Virtual Production
    • Government
    • Medical Devices
    • Software
    • Digital Twins

    Main Navigation - Mega Menu

    Main Navigation - Mega Menu

    Main Navigation - Mega Menu

    Main Navigation - Mega Menu

  • Customers
  • Resources

    Main Navigation - Mega Menu

    • Explore Resources
    • Papers & Videos
    • Recorded Webinars
    • Events & Webinars
    • Blog
    • Free Trials
    • Subscribe
    Version Control in Virtual Production

    Version Control in Virtual Production Field Guide

    Read Now
  • Support
  • Services

    Main Navigation - Mega Menu

    • Consulting/Professional Services
    • Training

    Main Navigation - Mega Menu

    • Consulting Services Overview
    • Akana
    • BlazeMeter
    • Helix ALM
    • Helix Core
    • Helix QAC
    • Klocwork
    • Methodics IPLM
    • OpenLogic
    • Perfecto
    • Zend

    Main Navigation - Mega Menu

    • Training Overview
    • Hansoft
    • Helix ALM
    • Helix Core
    • Helix QAC
    • Klocwork
    • OpenLogic
    • Perfecto
    • Zend
  • Try Free
  • Downloads
  • Integrations
  • Blog
  • Company

    Main Navigation - Mega Menu

    • About Us
    • Careers
    • Culture
    • Events
    • Partners
    • Press
    • Team
  • Contact

Version 4.0

High Integrity C++ Coding Standard

Released October 3, 2013

Request PDF Version
High Integrity C++ Coding Standard
0. Introduction
1. General
2. Lexical Conventions
3. Basic Concepts
4. Standard Conversions
5. Expressions
6. Statements
7. Declarations
8. Definitions
9. Classes
10. Derived Classes
11. Member Access Control
12. Special Member Functions
13. Overloading
14. Templates
15. Exception Handling
16. Preprocessing
17. Standard Library
18. Concurrency
19. References
20. Revision History
21. Conditions of Use

12. Special Member Functions

12.1 Conversions


12.1.1 Do not declare implicit user defined conversions

A user-defined conversion can occur through the use of a conversion operator or a conversion constructor (a constructor that accepts a single argument). A compiler can invoke a single user defined conversion in a standard conversion sequence, but only if the operator or constructor is declared without the explicit keyword. It is better to declare all conversion constructors and operators explicit.

#include <cstdint>
   
class C
{
public:
C (const C&);                      // @@+ Compliant: copy constructor [email protected]@
C ();                              // @@+ Compliant: default constructor [email protected]@
C (int32_t, int32_t);              // @@+ Compliant: more than one non-default argument [email protected]@
                                               
explicit C (int32_t);              // @@+ Compliant [email protected]@
C (double);                        // @@- Non-Compliant [email protected]@
C (float f, int32_t i = 0);        // @@- Non-Compliant [email protected]@
C (int32_t i = 0, float f = 0.0);  // @@- Non-Compliant: default constructor, [email protected]@
                                   // @@-   but also a conversion constructor [email protected]@
operator int32_t () const;         // @@- Non-Compliant [email protected]@
explicit operator double () const; // @@+ Compliant [email protected]@
};

References

  • HIC++ v3.3 – 3.2.3
  • HIC++ v3.3 – 3.1.10
  • HIC++ v3.3 – 3.1.11

View references >

12.2 Destructors


12.2.1 Declare virtual, private or protected the destructor of a type used as a base class

If an object will ever be destroyed through a pointer to its base class, then the destructor in the base class should be virtual. If the base class destructor is not virtual, then the destructors for derived classes will not be invoked. Where an object will not be deleted via a pointer to its base, then the destructor should be declared with protected or private access. This will result in a compile error should an attempt be made to delete the object incorrectly.

#include <cstdint>
   
class A
{
public:
~A ();         // @@- Non-Compliant [email protected]@
};
               
class B : public A
{
};
               
class C
{
public:
virtual ~C (); // @@+ Compliant [email protected]@
};
               
class D : public C
{
};
               
class E
{
protected:
~E ();         // @@+ Compliant [email protected]@
};
               
class F : public E
{
};

References

  • HIC++ v3.3 – 3.3.2

View references >

12.3 Free Store


12.3.1 Correctly declare overloads for operator new and delete

Operator new and operator delete should work together. Overloading operator new means that a custom memory management scheme is in operation for a particular class or program. If a corresponding operator delete (plain or array) is not provided the memory management scheme is incomplete. Additionally, if initialization of the allocated object fails with an exception, the C++ runtime will try to call an operator delete with identical parameters as the called operator new, except for the first parameter. If no such operator delete can be found, the memory will not be freed. If this operator delete does not actually need to perform any bookkeeping, one with an empty body should be defined to document this in the code. When declared in a class, operator new and operator delete are implicitly static members; explicitly including the static specifier in their declarations helps to document this.

#include <cstddef>
   
class C
{
public:
static void* operator new (std::size_t size);
static void operator delete (void* ptr);   // @@+ Compliant [email protected]@
   
void* operator new [] (std::size_t size);  // @@- Non-Compliant [email protected]@
};          


References

  • HIC++ v3.3 – 12.6
  • HIC++ v3.3 – 12.7

View references >

12.4 Initializing Bases and Members


12.4.1 Do not use the dynamic type of an object unless the object is fully constructed

Expressions involving:

  • A call to a virtual member function,
  • Use of typeid, or
  • A cast to a derived type using dynamic_cast

These are said to use the dynamic type of the object. Special semantics apply when using the dynamic type of an object while it is being constructed or destructed. Moreover, it is undefined behavior if the static type of the operand is not (or is not a pointer to) the constructor’s or destructor’s class or one of its base classes. In order to avoid misconceptions and potential undefined behavior, such expressions should not be used while the object is being constructed or destructed.

#include <typeinfo>
class A
{
public:
virtual void foo ();
virtual void bar ();
};
               
class B : public A
{
public:
B();
~B();
                 
void foo () override;
};
               
class C : public B
{
public:
void foo () override;
void bar () override;
};
     
B::B()
{
foo ();                   // @@- Non-Compliant: B::foo () is called and never C::foo () [email protected]@
B::foo ();                // @@+ Compliant: not a virtual call [email protected]@
typeid (*this);           // @@- Non-Compliant [email protected]@
}
               
B::~B()
{
bar ();                   // @@- Non-Compliant: A::bar () is called and never C::bar () [email protected]@
A::bar ();                // @@+ Compliant: not a virtual call [email protected]@
dynamic_cast <A*> (this); // @@+ Compliant: dynamic type is not needed for a downcast [email protected]@
dynamic_cast <C*> (this); // @@- Non-Compliant [email protected]@
}
     
void foo ()
{
C c;
}

References

  • HIC++ v3.3 – 3.3.13
  • JSF AV C++ Rev C – 71
  • MISRA C++:2008 – 12-1-1

View references >

12.4.2 Ensure that a constructor initializes explicitly all base classes and non-static data members

A constructor should completely initialize its object. Explicit initialization reduces the risk of an invalid state after successful construction. All virtual base classes and direct non-virtual base classes should be included in the initialization list for the constructor. A copy or move constructor should initialize each non-static data member in the initialization list, or if this is not possible then in constructor body. For other constructors, each non-static data member should be initialized in the following way, in order of preference:

  • Non-static data member initializer (NSDMI).
  • In initialization list.
  • In constructor body.

For many constructors, this means that the body becomes an empty block.

class C
{
public:
C () : m_j (0), m_a () {}           // @@+ Compliant [email protected]@
                 
// @@- Non-Compliant: m_a not initialized [email protected]@
C (C const & other) : m_i (other.m_i), m_j (other.m_j) {}
                 
explicit C (int32_t j) : m_j (j) {} // @@- Non-Compliant: m_a not initialized [email protected]@
                 
private:
int32_t m_i = 0;
int32_t m_j;
int32_t m_a [10];
};

References

  • HIC++ v3.3 – 3.2.1

View references >

12.4.3 Do not specify both an NSDMI and a member initializer in a constructor for the same non static member

NSDMI stands for ‘non static data member initializer’. This syntax, introduced in the 2011 C++ Language Standard, allows for the initializer of a member to be specified along with the declaration of the member in the class body. To avoid confusion as to the value of the initializer actually used, if a member has an NSDMI then it should not subsequently be initialized in the member initialization list of a constructor.

#include <cstdint>
   
class A
{
public:
A()
: m_i1(1)        // @@+ Compliant [email protected]@
, m_i2(1)        // @@- Non-Compliant [email protected]@
{
}
   
private:
int m_i1;
int m_i2 = 0;    // @@- Non-Compliant [email protected]@
int m_i3 = 0;    // @@+ Compliant [email protected]@
};

Exception

The move/copy constructors are exempt from this rule, as in this context the rule conflicts with Rule 12.4.2: ”Ensure that a constructor initializes explicitly all base classes and non-static data members”, which takes precedence.

For Example:

# include <cstdint>
class A
{
public :
A(A const & rhs)
: m_i1 (rhs. m_i1 ) // Compliant
, m_i2 (rhs . m_i2 ) // Compliant
{
}
private :
int32_t m_i1 ;
int32_t m_i2 = 0;
};

12.4.4 Write members in an initialization list in the order in which they are declared

Regardless of the order of member initializers in a initialization list, the order of initialization is always:

  • Virtual base classes in depth and left to right order of the inheritance graph.
  • Direct non-virtual base classes in left to right order of inheritance list.
  • Non-static member data in order of declaration in the class definition.

To avoid confusion and possible use of uninitialized data members, it is recommended that the initialization list matches the actual initialization order.

#include <cstdint>
   
class B {};
   
class VB : public virtual B {};
   
class C {};
   
class DC : public VB, public C
{
public:
DC()
: B(), VB(), C(), i (1), c() // @@+ Compliant [email protected]@
{}
   
private:
int32_t i;
C c;
};

References

  • HIC++ v3.3 – 3.2.2

View references >

12.4.5 Use delegating constructors to reduce code duplication

Delegating constructors can help reduce code duplication by performing initialization in a single constructor. Using delegating constructors also removes a potential performance penalty with using an ‘init’ method, where initialization for some members occurs twice.

#include <cstdint>
   
// @@- Non-Compliant [email protected]@
class A1 {
public:
A1()
{
init(10, 20);
}
                 
A1(int i)
{
init(i, 20);
}
private:
void init(int32_t i, int32_t j);
   
private:
int32_t m_i;
int32_t m_j;
};
               
// @@+ Compliant [email protected]@
class A2 {
public:
A2()
: A2(10, 20)
{
}
                 
A2(int32_t i)
: A2(i, 20)
{
}
                 
private:
A2(int32_t i, int32_t j)
: m_i(i)
, m_j(j)
{
}
   
private:
int32_t m_i;
int32_t m_j;
};

12.5 Copying and Moving Class Objects


12.5.1 Define explicitly =default or =delete implicit special member functions of concrete classes

A compiler may provide some or all of the following special member functions:

  • Destructor
  • Copy constructor
  • Copy assignment operator
  • Move constructor
  • Move assignment operator

The set of functions implicitly provided depends on the special member functions that have been declared by the user and also the special members of base classes and member objects. The compiler generated versions of these functions perform a bitwise or shallow copy, which may not be the correct copy semantics for the class. It is also not clear to clients of the class if these functions can be used or not. To resolve this, the functions should be defined with =delete or =default thereby fully documenting the class interface.

#include <cstdint>
   
class A1     // @@- Non-Compliant: Includes implicitly declared special members [email protected]@
{
public:
A1();
~A1();
   
private:
int32_t * m_i;
};
   
class A2     // @@+ Compliant: No implicitly declared special members [email protected]@
{
public:
A2();
~A2();
A2(A2 const &) = default;
A2 & operator=(A2 const &) & = delete;
   
private:
int32_t * m_i;
};

Note: As this rule is limited to concrete classes, it is the responsibility of the most derived class to ensure that the object has correct copy semantics for itself and for its sub-objects.

References

  • HIC++ v3.3 – 3.1.3
  • HIC++ v3.3 – 3.1.13

View references >

12.5.2 Define special members =default if the behavior is equivalent

The implicitly defined copy constructor for a class X with two bases and two members will be defined as:

Copy Constructor:

X::X(X const & rhs)
: base1 (rhs)
, base2 (rhs )
, mbr1 (rhs . mbr1 )
, mbr2 (rhs . mbr2 )
{
}

The implicitly defined move constructor for the same class X will be defined as:

Move Constructor:

X::X(X && rhs)
: base1 (std :: move (rhs ))
, base2 (std :: move (rhs ))
, mbr1 (std :: move (rhs . mbr1 ))
, mbr2 (std :: move (rhs . mbr2 ))
{
}

Finally, the implicitly defined destructor will be defined as:

Destructor:

X::~X()
{
}

If a class contains a user defined version of a member with the same definition as would be provided by the compiler, then it will be less error prone and more maintainable to replace the definition with =default.

#include <cstdint>
   
class A
{
public:
~A()                // @@- Non-Compliant [email protected]@
{
}
                   
A(A const & rhs)    // @@- Non-Compliant [email protected]@
: mbr(rhs.mbr)
{
}
   
A(A &&) = default;  // @@+ Compliant [email protected]@
   
private:
int32_t mbr;
};

References

  • JSF AV C++ Rev C – 80

View references >

12.5.3 Ensure that a user defined move/copy constructor only moves/copies base and member objects

The human clients of a class will expect that the copy constructor can be used to correctly copy an object of class type. Similarly, they will expect that the move constructor correctly moves an object of class type. Similarly, a compiler has explicit permission in the C++ Standard to remove unnecessary copies or moves, on the basis that these functions have no other side-effects other than to copy or move all bases and members.

#include <cstdint>
#include <utility>
                 
class Base
{
public:
Base ()
: m_j (-1)
{
}
                                 
Base (Base const & rhs)
: m_j (rhs.m_j)
{
}
                                 
Base (Base && rhs) noexcept
: m_j (std::move (rhs.m_j))
{
}
                                 
private:
int32_t m_j;
};
                 
void foo ();
                 
class Derived1 : public Base
{
public:
Derived1 (Derived1 const & rhs)
: Base (rhs)
, m_i (rhs.m_i)
{
foo (); // @@- Non-Compliant: unrelated side effect [email protected]@
}
                                 
Derived1 (Derived1 && rhs) noexcept
: Base (std::move (rhs))
, m_i (std::move (rhs.m_i))
{
foo (); // @@- Non-Compliant: unrelated side effect [email protected]@
}
                 
private:
int32_t m_i;
};
                 
class Derived2 : public Base
{
public:
Derived2 (Derived2 const & rhs)      // @@+ Compliant [email protected]@
: Base (rhs)
, m_i (rhs.m_i)
{
}
                                 
Derived2 (Derived2 && rhs) noexcept  // @@+ Compliant [email protected]@
: Base (std::move (rhs))
, m_i (std::move (rhs.m_i))
{
}
                 
private:
int32_t m_i;
};

References

  • MISRA C++:2008 – 12-8-1

View references >

12.5.4 Declare noexcept the move constructor and move assignment operator

A class provides the Strong Exception Guarantee if after an exception occurs, the objects maintain their original values. The move members of a class explicitly change the state of their argument. Should an exception be thrown after some members have been moved, then the Strong Exception Guarantee may no longer hold as the from object has been modified. It is especially important to use noexcept for types that are intended to be used with the standard library containers. If the move constructor for an element type in a container is not noexcept then the container will use the copy constructor rather than the move constructor.

#include <utility>
#include <cstdint>
   
class B
{
public:
B (B && rhs) noexcept         // @@+ Compliant [email protected]@
: m_p (std::move (rhs.m_p))
{
rhs.m_p = 0;
}
   
private:
int32_t * m_p;
};
   
class A
{
public:
A (A && rhs)                  // @@- Non-Compliant [email protected]@
: m_a (std::move (rhs.m_a))
, m_b ((rhs.m_b) ? std::move (rhs.m_b) : throw 0)
{
}
   
A& operator = (A&&) noexcept; // @@+ Compliant [email protected]@
                   
private:
B m_a;
int32_t m_b;
};

12.5.5 Correctly reset moved-from handles to resources in the move constructor

The move constructor moves the ownership of data from one object to another. Once a resource has been moved to a new object, it is important that the moved-from object has its handles set to a default value. This will ensure that the moved-from object will not attempt to destroy resources that it no longer manages on its destruction. The most common example of this is to assign nullptr to pointer members.

#include <utility>
#include <cstdint>
   
class A1
{
public:
A1(A1 && rhs) noexcept         // @@- Non-Compliant [email protected]@
: m_p(std::move(rhs.m_p))
{
}
   
~A1()
{
delete m_p;                  // Moved-from object will attempt to delete
                             // resource owned by other object
}
   
private:
int32_t * m_p;
};
   
class A2
{
public:
A2(A2 && rhs) noexcept         // @@+ Compliant [email protected]@
: m_p(std::move(rhs.m_p))
{
rhs.m_p = nullptr;
}
   
~A2()
{
delete m_p;                  // Moved-from object will not delete
                             // resource owned by other object
}
   
private:
int32_t * m_p;
};

12.5.6 Use an atomic, non-throwing swap operation to implement the copy and move assignment operators

Implementing the copy assignment operator using a non throwing swap provides the Strong Exception Guarantee for the operations. In addition, the implementation of each assignment operator is simplified without requiring a check for assignment to self.

#include <utility>
#include <cstdint>
                 
class A1
{
public:
A1(A1 const & rhs)
: m_p1(new int32_t (*rhs.m_p1))
, m_p2(new int32_t (*rhs.m_p2))
{
}
   
A1(A1 && rhs) noexcept
: m_p1(std::move (rhs.m_p1))
, m_p2(std::move (rhs.m_p2))
{
rhs.m_p1 = nullptr;
rhs.m_p2 = nullptr;
}
   
~A1()
{
delete m_p1;
delete m_p2;
}
   
A1 & operator=(A1 const & rhs) &     // @@- Non-Compliant [email protected]@
{
if (this != &rhs)
{
m_p1 = new int32_t (*rhs.m_p1);
   
// An exception here would result in a memory leak for m_p1
m_p2 = new int32_t (*rhs.m_p2);
}
return *this;
}
   
A1 & operator=(A1 && rhs) & noexcept // @@- Non-Compliant [email protected]@
{
if (this != &rhs)
{
m_p1 = std::move (rhs.m_p1);
m_p2 = std::move (rhs.m_p2);
rhs.m_p1 = nullptr;
rhs.m_p2 = nullptr;
}
return *this;
}
   
private:
int32_t * m_p1;
int32_t * m_p2;
};
   
class A2
{
public:
A2(A2 const & rhs)
: m_p1(new int32_t (*rhs.m_p1))
, m_p2(new int32_t (*rhs.m_p2))
{
}
   
A2(A2 && rhs) noexcept
: m_p1(std::move (rhs.m_p1))
, m_p2(std::move (rhs.m_p2))
{
rhs.m_p1 = nullptr;
rhs.m_p2 = nullptr;
}
   
~A2()
{
delete m_p1;
delete m_p2;
}
   
A2 & operator=(A2 rhs) &             // @@+ Compliant:  Note: 'rhs' is by value [email protected]@
{
swap (*this, rhs);
return *this;
}
   
A2 & operator=(A2 && rhs) & noexcept // @@+ Compliant [email protected]@
{
A2 tmp (std::move (rhs));
swap (*this, tmp);
return *this;
}
   
void swap(A2 & lhs, A2 & rhs) noexcept
{
std::swap (lhs.m_p1, rhs.m_p1);
std::swap (lhs.m_p2, rhs.m_p2);
}
   
private:
int32_t * m_p1;
int32_t * m_p2;
};

References

  • HIC++ v3.3 – 3.1.4

View references >

12.5.7 Declare assignment operators with the ref-qualifier &

In the 2003 C++ language standard, user declared types differed from built-in types in that it was possible to have a ‘modifiable rvalue’.

#include <cstdint>
   
class A {
public:
A();
A & operator*=(int32_t);    // @@- Non-Compliant [email protected]@
};
A f1();
int32_t f2();
int main ()
{
f1() *= 10;    // Temporary result of 'f()' multiplied by '10'
f2() *= 10;    // Compile error
}

The 2011 C++ language standard allows for a function to be declared with a reference qualifier. Adding & to the function declaration ensures that the call can only be made on lvalue objects, as is the case for the built-in operators.

#include <cstdint>
   
class A {
public:
A();
A & operator*=(int32_t) &;  // @@+ Compliant [email protected]@
};
A f1();
int32_t f2();
int main ()
{
f1() *= 10;    // Compile error
f2() *= 10;    // Compile error
}

References

  • HIC++ v3.3 – 3.1.5

View references >

12.5.8 Make the copy assignment operator of an abstract class protected or define it =delete

An instance of an abstract class can only exist as a subobject for a derived type. A public copy assignment operator would allow for incorrect partial assignments to occur. The copy assignment operator should be protected, or alternatively defined =delete if copying is to be prohibited in this class hierarchy.

#include <cstdint>
               
class A
{
public:
virtual ~A () = 0;         
A& operator = (A const &) &;           // @@- Non-Compliant [email protected]@
};
               
class AA : public A
{
};
               
void foo()
{
AA obj1;
AA obj2;
                
A* ptr1 = &obj1;
A* ptr2 = &obj2;
                
*ptr1 = *ptr2; // partial assignment
}
   
class B
{
public:
virtual ~B () = 0;
                 
protected:
B& operator = (B const &) &;           // @@+ Compliant [email protected]@
};
               
class C
{
public:
virtual ~C () = 0;
                 
protected:
C& operator = (C const &) & = default; // @@+ Compliant [email protected]@
};
   
class D
{
public:
virtual ~D () = 0;
D& operator = (D const &) & = delete;  // @@+ Compliant [email protected]@
};

References

  • HIC++ v3.3 – 3.3.14

View references >

Request PDF Version

 

 

Book traversal links for 12. Special Member Functions

  • ‹ 11. Member Access Control
  • High Integrity C++ Coding Standard
  • 13. Overloading ›

Footer menu

  • Products
    • Plan
    • Helix ALM
    • Hansoft
    • Create & Develop
    • Helix Core
    • Helix4Git
    • Helix DAM
    • Helix TeamHub
    • Helix Swarm
    • Methodics IPLM
    • VersIC
    • Test & Validate
    • Helix QAC
    • Klocwork
    • Operate, Manage, & Scale
    • SourcePro
    • HostAccess
    • HydraExpress
    • PV-WAVE
    • Stingray
    • Visualization
  • Solutions
    • By need
    • Application Lifecycle Management
    • Agile Project Management
    • DevOps
    • Version Control
    • IP Lifecycle Management
    • Static Analysis
    • Audit & Compliance
    • Backlog Management
    • Project Portfolio Management
    • By industry
    • Aerospace & Defense
    • Automotive
    • Embedded Systems
    • Semiconductor
    • Energy & Utilities
    • Finance
    • Game Development
    • Virtual Production
    • Government
    • Life Sciences
    • Software
  • Services
    • Consulting/Professional Services
    • Consulting Services Overview
    • Akana
    • BlazeMeter
    • Helix ALM
    • Helix Core
    • Helix QAC
    • Klocwork
    • Methodics IPLM
    • OpenLogic
    • Perfecto
    • Zend
    • Training
    • Training Overview
    • Hansoft
    • Helix ALM
    • Helix Core
    • Helix QAC
    • Klocwork
    • OpenLogic
    • Perfecto
    • Zend
  • Resources
    • Papers & Videos
    • Events & Webinars
    • Recorded Webinars
    • Blog
    • Perforce U
  • Support
  • Customers
    • Case Studies
  • About
    • Our Team
    • Our Culture
    • Careers
    • Press
    • Contact Us
  • Partners
    • Integrations
    • Resellers
  • Quick links
    • Free Trials
    • Subscription Center
    • Customer Support Login
    • Educational Licenses
    • How to Buy
Home
Perforce

Copyright © Perforce Software, Inc. All rights reserved.  |  Sitemap  |  Terms of Use  |  Privacy Policy

Social menu

  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • RSS
Send Feedback