The book and accompanying software incorporate simple and easy-to-understand projects such as digital-to-analog conversion, analog to digital conversion, DC and Stepper motor control, temperature and voltage measurement, PC-based timing, or basic data acquisition. The types of courses the book complements include control engineering, electronics, computing, and mechatronics. Convert currency.
Add to Basket. Condition: New. Seller Inventory More information about this seller Contact this seller. Book Description Springer, New Book. Shipped from US within 10 to 14 business days. Established seller since Seller Inventory IQ Condition: Neu. Unique and original approach to use the PC to do real things- not just number crunching and graphics - but writing programs to interact with the outside world. Includes a purpose-designed circuit board pp.
Delivered from our UK warehouse in 4 to 14 business days. Book Description Springer. Seller Inventory ING Book Description Springer Verlag, For example, arrays in J have to contain the same data type. Let's say you want to pass an array with an integer and a string into one of your verbs. In that case you need a box.
A box in J is a data type that supports heterogeneous values. Here's how we work with boxes:. We then use the dyadic verb , called Append in J to create an array out of our two boxes. The result of Append is assigned to our variable b. You also see that J has a nice printed representation of our boxed values. Finally we meet the monadic verb called Tally that counts the number of items in our boxed array.
Just as we'd expect, Tally reports two items. Armed with our basic J knowledge we're ready to get some serious business going by starting to manipulate verbs just as if they were data too. The J language has several functional elements although it's not a strict functional language. However, it does take the function abstraction a step further. The basic idea in functional programming is that functions are first-class citizens. This promise looks rather shallow once we see its realization in different languages. Sure, we can pass functions as arguments, return functions from other functions and even compose functions.
For example, what would it mean to subtract one function from another? Or to calculate the derivate of a function? I'd say both of these examples make sense from a mathematical perspective, yet Clojure doesn't know how to do it and neither does Scala nor F. This is where J takes off. Again we'll start simple. We talked about J's terminology earlier and so far we've met verbs and adverbs. J also has conjunctions. In natural language grammar, a conjunction is something that connects different words and phrases.
The power conjunction applies a given verb n times. Here's how it works when applied to our Double verb:. Let's capture that in a user defined verb, tacit style:. As you see in the example above, our user defined verb threeTimes automatically generalizes to whole arrays. Instead of spending precious code on loops or iterations, we just let the language do the job for us.
Interfacing with C++: Programming Real-World Applications
That leaves our code free to focus on the stuff that actually does something, the core of the problem we're trying to solve. There's a particular beauty to conjunctions. But J's way of manipulating functions go deeper. We can let the language inverse the meaning of a verb. As we'll see soon, inversing verbs is more than just a neat party trick; Once we have the ability of automatically inversing a function we are able to abstract several common programming tasks using succinct idiomatic expressions.
As I decided to learn the J language I looked for some small yet realistic problems to work on. The competition had a simple and interesting problem labelled How tweet it is. The task here is to shorten a message, yet retain most of its readability, by removing interior vowels from words. Let's give it a try. The first step in this task is to tokenize the string. That's straightforward with J's Words verb, written ;: :.
The ;: verb splits our string on its separators. It also partitions the resulting sub-string into a box since the tokens have different lengths. We let the variable b refer to our boxed array so that we can play around with it in the J interpreter and iterate towards our solution. The next step towards a tweetable sentence is to remove the interior vowels. This is fairly straightforward, but the details would distract us from our main topic of function inverses as we would need to learn more J verbs.
To use our trimWord verb we need to take the words out of the box, apply trimWord , and put the results back into a boxed array. As a programmer, we immediately see that. More interesting, the J language knows about it. J has a unique language feature that lets you inverse the meaning of a verb. It's a mechanism that works on most built-in verbs and, fascinatingly, also on most of our own user defined verbs. And in the cases where J isn't able to deduce an inverse automatically you can teach J about it by assigning an inverse yourself.
So what happens if we apply the power conjunction -1 times? That's right - we get an inverse that undoes the effect of applying the particular verb. Let's play around with this idea in the J interpreter to see how it may solve our tweetable problem. I've introduced comments NB. The example above shows a mathematical inverse like plus and minus. We also see a logical relationship between box and unbox those kind of non-mathematical relationships are the reason J prefers the term obverse over inverse. So far I hope you find the inverse trick just as cool as I do.
But how does it apply to our tweetable problem? Well, let's recap the pattern we want to express: first we'll unbox our words, then we let J apply trimWord to each of the words before we box the results. As we'll soon see, the general form of this pattern is common to many familiar programming problems. That's why J provides an idiomatic expression for it. Under works on two verbs that form a pipeline: the first verb is applied, then the second verb is applied to that result before the inverse of the first verb is applied to form the final result.
Let's see it in action:. And there we are - we have a tweetable sentence. However, there's a bit more work before we're done done. That's good because it gives us an opportunity to uncover some more J ideas. Our solution so far works as long as we have our words in an array of boxes. By writing directly to the target elements, we will get only the basic guarantee rather than the strong guarantee offered by the swap technique.
Beware of self-assignment. See copy constructor vs. That is the generally assumed semantics. After a copy x and y can be independent objects value semantics, the way non-pointer built-in types and the standard-library types work or refer to a shared object pointer semantics, the way pointers work. Value semantics is the simplest to reason about and what the standard-library facilities expect. The default assignment generated from members that handle self-assignment correctly handles self-assignment. You can handle self-assignment by explicitly testing for self-assignment, but often it is faster and more elegant to cope without such a test e.
This is obviously safe and apparently efficient. However, what if we do one self-assignment per million assignments? All the cost is carried by the rare case of self-assignment. Ideally, that moved-from should be the default value of the type. Ensure that unless there is an exceptionally good reason not to. However, not all types have a default value and for some types establishing the default value can be expensive.
The standard requires only that the moved-from object can be destroyed. Often, we can easily and cheaply do better: The standard library assumes that it is possible to assign to a moved-from object. Always leave the moved-from object in some necessarily specified valid state. Not enforceable Look for assignments to members in the move operation. If there is a default constructor, compare those assignments to the initializations in the default constructor. However, std::swap is implemented using move operations so if you accidentally do swap a, b where a and b refer to the same object, failing to handle self-move could be a serious and subtle error.
Apparently this has not been a problem in about 10 years of experimental and production use. Please contact the editors if you find a counter example. The rule here is more caution and insists on complete safety. Here is a way to move a pointer without a test imagine it as code in the implementation a move assignment :. A non-throwing move will be used more efficiently by standard-library and language facilities.
This Vector2 is not just inefficient, but since a vector copy requires allocation, it can throw. A polymorphic class is a class that defines or inherits at least one virtual function. It is likely that it will be used as a base class for other derived classes with polymorphic behavior.
If it is accidentally passed by value, with the implicitly generated copy constructor and assignment, we risk slicing: only the base portion of a derived object will be copied, and the polymorphic behavior will be corrupted. If you need to create deep copies of polymorphic objects, use clone functions: see C. In addition to the operations for which the language offer default implementations, there are a few operations that are so foundational that it rules for their definition are needed: comparisons, swap , and hash.
- A Few Seconds of Panic: A Sportswriter Plays in the NFL.
- The Brevity of Array Languages?
- Featured channels.
- Interfacing with C++: Programming Real-World Applications?
- C.other: Other default operation rules.
- Nonlinear Control Systems: An Introduction.
The compiler is more likely to get the default semantics right and you cannot implement these functions better than the compiler. Because we defined the destructor, we must define the copy and move operations. Writing out the bodies of the copy and move operations is verbose, tedious, and error-prone. A compiler does it better. Moderate The body of a special operation should not have the same accessibility and semantics as the compiler-generated version, because that would be redundant.
To achieve that its copy operations are deleted. The elimination of a default operation is should be based on the desired semantics of the class. The function called will be that of the object constructed so far, rather than a possibly overriding function in a derived class. This can be most confusing. Worse, a direct or indirect call to an unimplemented pure virtual function from a constructor or destructor results in undefined behavior.
Note that calling a specific explicitly qualified function is not a virtual call even if the function is virtual. See also factory functions for how to achieve the effect of a call to a derived class function without risking undefined behavior. There is nothing inherently wrong with calling virtual functions from constructors and destructors. The semantics of such calls is type safe. However, experience shows that such calls are rarely needed, easily confuse maintainers, and become a source of errors when used by novices.
A swap can be handy for implementing a number of idioms, from smoothly moving objects around to implementing assignment easily to providing a guaranteed commit function that enables strongly error-safe calling code. Consider using swap to implement copy assignment in terms of copy construction. See also destructors, deallocation, and swap must never fail. The standard-library containers and algorithms will not work correctly if a swap of an element type fails.
This is not just slow, but if a memory allocation occurs for the elements in tmp , this swap may throw and would make STL algorithms fail if used with them. Simple When a class has a swap member function, it should be declared noexcept. A swap may not fail. Asymmetric treatment of operands is surprising and a source of errors where conversions are possible.
The alternative is to make two failure states compare equal and any valid state compare false against the failure state. This rule applies to all the usual comparison operators:! A container is an object holding a sequence of objects of some type; std::vector is the archetypical container. A resource handle is a class that owns a resource; std::vector is the typical resource handle; its resource is its sequence of elements.
There are of course other fundamentally sound design styles and sometimes reasons to depart from the style of the standard library, but in the absence of a solid reason to differ, it is simpler and easier for both implementers and users to follow the standard. In particular, std::vector and std::map provide useful relatively simple models. Here, the STL style is followed, but incompletely. Provide only as much functionality as makes sense for a specific container.
The key is to define the conventional constructors, assignments, destructors, and iterators as meaningful for the specific container with their conventional semantics. From that base, the container can be expanded as needed.
Here, special constructors from std::vector were added. If meaningful, make a container Regular the concept. In particular, ensure that an object compares equal to its copy. Containers tend to get large; without a move constructor and a copy constructor an object can be expensive to move around, thus tempting people to pass pointers to it around and getting into resource management problems. A function object is an object supplying an overloaded so that you can call it. Function objects should be cheap to copy and therefore passed by value.
A class hierarchy is constructed to represent a set of hierarchically organized concepts only. Typically base classes act as interfaces. There are two major uses for hierarchies, often named implementation inheritance and interface inheritance. Direct representation of ideas in code eases comprehension and maintenance. Make sure the idea represented in the base class exactly matches all derived types and there is not a better way to express it than using the tight coupling of inheritance.
Do not use inheritance when simply having a data member will do. Usually this means that the derived type needs to override a base virtual function or needs access to a protected member. Here most overriding classes cannot implement most of the functions required in the interface well. Thus the base class becomes an implementation burden. Furthermore, the user of Container cannot rely on the member functions actually performing meaningful operations reasonably efficiently; it may throw an exception instead. A class is more stable less brittle if it does not contain data.
The Derived is delete d through its Goof interface, so its string is leaked. Give Goof a virtual destructor and all is well. A user can now use D1 s and D2 s interchangeably through the interface provided by Device. Furthermore, we can update D1 and D2 in ways that are not binary compatible with older versions as long as all access goes through Device. A class with a virtual function is usually and in general used via a pointer to base. Usually, the last user has to call delete on a pointer to base, often via a smart pointer to base, so the destructor should be public and virtual.
Less commonly, if deletion through a pointer to base is not intended to be supported, the destructor should be protected and nonvirtual; see C. Detection of mistakes. However, writing more than one of these three is both redundant and a potential source of errors. Implementation details in an interface make the interface brittle; that is, make its users vulnerable to having to recompile after changes in the implementation. Data in a base class increases the complexity of implementing the base and can lead to replication of code.
A pure interface class is simply a set of pure virtual functions; see I. In early OOP e. Even now, mixtures are not uncommon in old code bases and in old-style teaching material. The implementation of Shape::move is an example of implementation inheritance: we have defined move once and for all for all derived classes. The more code there is in such base class member function implementations and the more data is shared by placing it in the base, the more benefits we gain - and the less stable the hierarchy is.
The interface is now less brittle, but there is more work in implementing the member functions. For example, center has to be implemented by every class derived from Shape.
How can we gain the benefit of stable hierarchies from implementation hierarchies and the benefit of implementation reuse from implementation inheritance? One popular technique is dual hierarchies. There are many ways of implementing the idea of dual hierarchies; here, we use a multiple-inheritance variant.
- Schwartzs Manual of Surgery;
- Certified Information Systems Security Professional Engineering (CISSP-ISSEP) Secrets To Acing The Exam and Successful Finding And Landing Your Next Certified Information Systems Security Professional Engineering (CISSP-ISSEP) Certified Job.
- CPP and electronic circuit;
- Pakistan (Modern World Nations).
- Interfacing Programming Real World Applications by Jayantha Katupitiya Kim Bentley?
- List of top C & C++ books for programming enthusiasts!
To make this interface useful, we must provide its implementation classes here, named equivalently, but in the Impl namespace :. Now Shape is a poor example of a class with an implementation, but bear with us because this is just a simple example of a technique aimed at more complex hierarchies. Since each implementation is derived from its interface as well as its implementation base class we get a lattice DAG :. This can be useful when the implementation class has members that are not offered in the abstract interface or if direct use of a member offers optimization opportunities e.
Another related technique for separating interface and implementation is Pimpl. There is often a choice between offering common functionality as implemented base class functions and free-standing functions in an implementation namespace. Base classes gives a shorter notation and easier access to shared data in the base at the cost of the functionality being available only to users of the hierarchy.
Copying a polymorphic class is discouraged due to the slicing problem, see C. If you really need copy semantics, copy deeply: Provide a virtual clone function that will copy the actual most-derived type and return an owning pointer to the new object, and then in derived classes return the derived type use a covariant return type. Generally, it is recommended to use smart pointers to represent ownership see R. A trivial getter or setter adds no semantic value; the data item could just as well be public. Consider making such a class a struct — that is, a behaviorless bunch of variables, all public data and no member functions.
Note that we can put default initializers on member variables: C. Examples of non-trivial semantics would be: maintaining a class invariant or converting between an internal type and an interface type. Flag multiple get and set member functions that simply access a member without additional semantics. Redundant virtual increases run-time and object-code size.
A virtual function can be overridden and is thus open to mistakes in a derived class. A virtual function ensures code replication in a templated hierarchy. Now it is up to every derived Shape to manipulate the protected data correctly. This has been popular, but also a major source of maintenance problems. In a large class hierarchy, the consistent use of protected data is hard to maintain because there can be a lot of code, spread over a lot of classes.
The set of classes that can touch that data is open: anyone can derive a new class and start manipulating the protected data. Often, it is not possible to examine the complete set of classes, so any change to the representation of the class becomes infeasible. There is no enforced invariant for the protected data; it is much like a set of global variables. The protected data has de facto become global to a large body of code.
Protected data often looks tempting to enable arbitrary improvements through derivation. Often, what you get is unprincipled changes and errors. Prefer private data with a well-specified and enforced invariant. Alternative, and often better, keep data out of any class used as an interface. Prevention of logical confusion leading to errors. Is it a type that maintains an invariant or simply a collection of values? Data members in category A should just be public or, more rarely, protected if you only want derived classes to see them. All code in the system might as well see and manipulate them.
Data members in category B should be private or const. This is because encapsulation is important. This leads to brittle and tightly coupled code that quickly becomes a nightmare to maintain. Any code that inadvertently sets the data members to an invalid or unexpected combination of values would corrupt the object and all subsequent uses of the object.
Occasionally classes will mix A and B, usually for debug reasons. Flag any class that has non- const data members with different access levels. Not all classes will necessarily support all interfaces, and not all callers will necessarily want to deal with all operations. This is a very common use of inheritance because the need for multiple different interfaces to an implementation is common and such interfaces are often not easily or naturally organized into a single-rooted hierarchy.
Some forms of mixins have state and often operations on that state. If the operations are virtual the use of inheritance is necessary, if not using inheritance can avoid boilerplate and forwarding. This a relatively rare use because implementation can often be organized into a single-rooted hierarchy. Allow separation of shared data and interface. To avoid all shared data to being put into an ultimate base class. Interface is the root of an interface hierarchy and Utility is the root of an implementation hierarchy.
Here is a slightly more realistic example with an explanation. Without a using declaration, member functions in the derived class hide the entire inherited overload sets. Capping a hierarchy with final is rarely needed for logical reasons and can be damaging to the extensibility of a hierarchy. Not every class is meant to be a base class. Most standard-library classes are examples of that e. This rule is about using final on classes with virtual functions meant to be interfaces for a class hierarchy. Claims of performance improvements from final should be substantiated.
Too often, such claims are based on conjecture or experience with other languages. There are examples where final can be important for both logical and performance reasons. One example is a performance-critical AST hierarchy in a compiler or language analysis tool.
New derived classes are not added every year and only by library implementers. However, misuses are or at least have been far more common. Flag default arguments on virtual functions if they differ between base and derived declarations.
Interfacing with C++ - Programming Real-World Applications | Jayantha Katupitiya | Springer
Use of the other casts can violate type safety and cause the program to access a variable that is actually of type X to be accessed as if it were of an unrelated type Z :. Prefer virtual functions to casting. Prefer static polymorphism to hierarchy navigation where it is possible no run-time resolution necessary and reasonably convenient.
The latter is an inherently simpler operation that ought to be faster. The latter typeid is easily hand-crafted if necessary e. We added it to warn of the dangers of home-brew RTTI. This code may work as expected for years, just to fail on a new machine, new compiler, or a new linker that does not unify character literals. However, compatibility makes changes difficult even if all agree that an effort to optimize is worthwhile.
Casting to a reference expresses that you intend to end up with a valid object, so the cast must succeed. Since failure to find the class merely returns a null value, it can be tested during run time. This allows writing code that can choose alternative paths depending on the results. Contrast with C.
The objects are also sorted into views, according to their geometric attributes. Only its subclasses do. It also ensures exception safety in complex expressions. Subscripting the resulting base pointer will lead to invalid object access and probably to memory corruption. A virtual function call is safe, whereas casting is error-prone. A virtual function call reaches the most derived function, whereas a cast may reach an intermediate class and therefore give a wrong result especially as a hierarchy is modified during maintenance.
You can overload ordinary functions, template functions, and operators. You cannot overload function objects. Nonmember operators should be either friends or defined in the same namespace as their operands. Binary operators should treat their operands equivalently. If you use member functions, you need two.
Having different names for logically equivalent operations on different argument types is confusing, leads to encoding type information in function names, and inhibits generic programming. These three functions all print their arguments appropriately. Adding to the name just introduced verbosity and inhibits generic code. Having the same name for logically different functions is confusing and leads to errors when using generic programming.
The two operations are fundamentally different and unrelated so it is good that their names differ. The two operations are still fundamentally different and unrelated but the names have been reduced to their common minimum, opening opportunities for confusion. Fortunately, the type system will catch many such mistakes.
Implicit conversions can be essential e. Prefer explicitly named conversions until a serious need is demonstrated. Do not introduce implicit conversions through conversion operators or non- explicit constructors just to gain a minor convenience. The surprising and potentially damaging implicit conversion can occur in arbitrarily hard-to spot contexts, e. The string returned by ff is destroyed before the returned pointer into it can be used. Consider swap. It is a general standard-library function with a definition that will work for just about any type.
However, it is desirable to define specific swap s for specific types. For example, the general swap will copy the elements of two vector s being swapped, whereas a good specific implementation will not copy elements at all. The std::swap in f1 does exactly what we asked it to do: it calls the swap in namespace std. How do we get N::X considered? But that may not be what we wanted for generic code. There, we typically want the specific function if it exists and the general function if not. This is done by including the general function in the lookup for the function:.
Unlikely, except for known customization points, such as swap. The problem is that the unqualified and qualified lookups both have uses. Note that operator. Note that std::addressof always yields a built-in pointer. Ability for find operators using ADL. Avoiding inconsistent definition in different namespaces. Here, the meaning of! Remove the definition of namespace M and the confusion is replaced by an opportunity to make the mistake.
If a binary operator is defined for two types that are defined in different namespaces, you cannot follow this rule. This is a special case of the rule that helper functions should be defined in the same namespace as their class. A union is a struct where all members start at the same address so that it can hold only one member at a time. A union does not keep track of which member is stored so the programmer has to get it right; this is inherently error-prone, but there are ways to compensate.
A type that is a union plus an indicator of which member is currently held is called a tagged union , a discriminated union , or a variant. A union allows a single piece of memory to be used for different types of objects at different times. Consequently, it can be used to save memory when we have several objects that are never used at the same time.
A naked union is a union without an associated indicator which member if any it holds, so that the programmer has to keep track. Naked unions are a source of type errors. Note that the type error happened without any explicit cast. When we tested that program the last value printed was which is the integer value for the bit pattern for A well-designed tagged union is type safe. An anonymous union simplifies the definition of a class with a tag, union pair.
The code is somewhat elaborate. Handling a type with user-defined assignment and destructor is tricky. Saving programmers from having to write such code is one reason for including variant in the standard. It is undefined behavior to read a union member with a different type from the one with which it was written. Such punning is invisible, or at least harder to spot than using a named cast. Type punning using a union is a source of errors. The idea of Pun is to be able to look at the character representation of an int. If you wanted to see the bytes of an int , use a named cast:. Unfortunately, union s are commonly used for type punning.
Use that type instead of unsigned char or char for these operations. Enumerations are used to define sets of integer values and for defining types for such sets of values. Macros do not obey scope and type rules. Switching on an enumeration is common and the compiler can warn against unusual patterns of case labels. Such off-by-one switch -statements are often the results of an added enumerator and insufficient testing. Such code is not uncommon in code written before there were convenient alternative ways of specifying integer constants.
The default is the easiest to read and write. It avoids duplicate enumerator values. The default gives a consecutive set of values that is good for switch -statement implementations. Specifying values is necessary to match conventional values e. This section contains rules related to resources. A resource is anything that must be acquired and explicitly or implicitly released, such as memory, file handles, sockets, and locks.
The reason it must be released is typically that it can be in short supply, so even delayed release may do harm. An entity that is responsible for releasing a resource is called an owner. There are a few cases where leaks can be acceptable or even optimal: If you are writing a program that simply produces an output based on an input and the amount of memory needed is proportional to the size of the input, the optimal strategy for performance and ease of programming is sometimes simply never to delete anything. If you have enough memory to handle your largest input, leak away, but be sure to give a good error message if you are wrong.
Here, we ignore such cases. To avoid leaks and the complexity of manual resource management. Further, if any of the code marked Now all resource cleanup is automatic, performed once on all paths whether or not there is an exception. As a bonus, the function now advertises that it takes over ownership of the pointer.
What is Port? A handy wrapper that encapsulates the resource:. Arrays are best represented by a container type e. Such containers and views hold sufficient information to do range checking. The compiler does not read comments, and without reading other code you do not know whether p really points to n elements.
Use a span instead. C-style strings are passed as single pointers to a zero-terminated sequence of characters. Many current uses of pointers to a single element could be references. However, where nullptr is a possible value, a reference may not be a reasonable alternative.
We want owning pointers identified so that we can reliably and efficiently delete the objects pointed to by owning pointers. This code cannot all be rewritten ever assuming good code transformation software , especially not soon. For example, common vector implementations have one owning pointer and two non-owning pointers. It can be used without changing any code using it and without affecting ABIs. It is simply an indicator to programmers and analysis tools.
Returning a raw pointer imposes a lifetime management uncertainty on the caller; that is, who deletes the pointed-to object? In addition to suffering from the problem from leak , this adds a spurious allocation and deallocation operation, and is needlessly verbose. If Gadget is cheap to move out of a function i. If pointer semantics are required e. We want owners identified so that we can reliably and efficiently delete the objects pointed to by owning pointers. A scoped object is a local object, a global object, or a member. This implies that there is no separate allocation and deallocation cost in excess of that already used for the containing scope or object.
The following example is inefficient because it has unnecessary allocation and deallocation , vulnerable to exception throws and returns in the Global variables can be accessed from everywhere so they can introduce surprising dependencies between apparently unrelated objects. They are a notable source of errors. Warning : The initialization of global objects is not totally ordered. If you use a global object initialize it with a constant. Note that it is possible to get undefined initialization order even for const objects.
An immutable const global does not introduce the problems we try to avoid by banning global objects. NM: Obviously we can warn about non- const statics … do we want to?
- Lost and Fondue (CHEESE SHOP MYSTERY 02).
- Tom Swift among the Fire Fighters.
- Interfacing with C++.
In some implementations that delete and that free might work, or maybe they will cause run-time errors. There are applications and sections of code where exceptions are not acceptable. Some of the best such examples are in life-critical hard-real-time code. Beware that many bans on exception use are based on superstition bad or by concerns for older code bases with unsystematic resource management unfortunately, but sometimes necessary. In such cases, consider the nothrow versions of new. Flag explicit use of malloc and free.
The pointer returned by new should belong to a resource handle that can call delete. The bug may be latent: it may emerge only during maintenance.
If you have a naked new , you probably need a naked delete somewhere, so you probably have a bug. Simple Warn on any explicit use of new and delete. The use of the file handle in ifstream is simple, efficient, and safe. If you perform two explicit resource allocations in one statement, you could leak resources because the order of evaluation of many subexpressions, including function arguments, is unspecified.
In particular, the compiler can interleave execution of the two expressions: Memory allocation by calling operator new could be done first for both objects, followed by attempts to call the two Widget constructors. This subtle problem has a simple solution: Never perform more than one explicit resource allocation in a single expression statement. The best solution is to avoid explicit allocation entirely use factory functions that return owning objects:.
An array decays to a pointer, thereby losing its size, opening the opportunity for range errors. Use span to preserve size information. Flag  parameters. Use span instead. Simple Warn if the return value of new or a function call with return value of pointer type is assigned to a raw pointer. BS: breaking cycles is what you must do; temporarily sharing ownership is how you do it. Accepting a smart pointer to a widget is wrong if the function just needs the widget itself. It should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
A function that does not manipulate lifetime should take raw pointers or references instead. The rules in the following section also work for other kinds of third-party and custom smart pointers and are very useful for diagnosing common smart pointer errors that cause performance and correctness problems. You want the rules to work on all the smart pointers you use. Violating this rule is the number one cause of losing reference counts and finding yourself with a dangling pointer. Functions should prefer to pass raw pointers and references down call chains. At the top of the call tree where you obtain the raw pointer or reference from a smart pointer that keeps the object alive.
You need to be sure that the smart pointer cannot inadvertently be reset or reassigned from within the call tree below. To do this, sometimes you need to take a local copy of a smart pointer, which firmly keeps the object alive for the duration of the function and the call tree. Expressions and statements are the lowest and most direct way of expressing actions and computation. Declarations in local scopes are statements. For naming, commenting, and indentation rules, see NL: Naming and layout.
Code using a library can be much easier to write than code working directly with language features, much shorter, tend to be of a higher level of abstraction, and the library code is presumably already tested. Large parts of the standard library rely on dynamic allocation free store. These parts, notably the containers but not the algorithms, are unsuitable for some hard-real-time and embedded applications. Not easy. Look for messy loops, nested loops, long functions, absence of function calls, lack of use of non-built-in types.
Cyclomatic complexity? The more traditional and lower-level near-equivalent is longer, messier, harder to get right, and most likely slower:. Once the checking for overflow and error handling has been added that code gets quite messy, and there is the problem remembering to delete the returned pointer and the C-style strings that array contains. A declaration is a statement. A declaration introduces a name into a scope and may cause the construction of a named object. This function is by most measure too long anyway, but the point is that the resources used by fn and the file handle held by is are retained for much longer than needed and that unanticipated use of is and fn could happen later in the function.
In this case, it might be a good idea to factor out the read:. An index is conventionally called i and there is no hint about the meaning of the vector in this generic function, so v is as good name as any.